您的位置:首页 > 数据库 > MySQL

mysql 使用嵌套集实现无限分类

2014-04-22 15:48 295 查看
参考文章:

1.http://www.2cto.com/database/201303/194971.html

2.http://www.jb51.net/article/28020.htm

实现无线分类的方法还有邻接表,路径枚举,闭包表

创建表:

CREATE TABLE  nestedCategory(
id INT NOT NULL PRIMARY KEY,
title VARCHAR(20)  NOT NULL,
lft INT NOT NULL,
rgt INT NOT NULL
);


插入测试数据:

insert  into `nestedcategory`(`id`,`title`,`lft`,`rgt`) values (1,'Food',1,18),(2,'Fruit',2,11),(3,'Red',3,6),(4,'Cherry',4,5),(5,'Yellow',7,10),(6,'Banana',8,9),(7,'Meat',12,17),(8,'Beef',13,14),(9,'Pork',15,16);


结构图:



思路:树的前序遍历改进算法

1.通过树id查找 一个完成的树

(1)先根据id查找到当前结点的左右值lft,rgt

(2)在查找结点左值(右值)在lft 和rgt之间,并按照lft升序排序

(3)两条相邻的记录的右值如果前一条大于当前条的右值那么前一条为该条记录的父记录

2.给一个结点插入一个字节点

(1).获取该结点的左值lft

(2)更新所有结点的左值,条件是被更新的结点左值大于lft,

(3)跟新所有结点的右值,条件是被更新的结点的右值大于lft

(4)插入当前结点,当前结点的左值为lft+1,右值为lft+2

3.删除一个树

(1).获取结点的左值lft 和右值 rgt 记该树占用的数字个数len = rgt-lft +1;

(2).删除所有左值(右值)在lft和rgt之间的结点

(3).更新其他结点,把其他结点左右值都减去 len(这些左右值大于rgt)

简单的一个实现类:

<?php

/**
* mysql数据库类别无限分类,嵌套集实现\
* 实现功能不检查错误
* @author prg
* @copyright 2014/4/21
*/
class nestedCategory
{
private $db;
private $tree; //保存结果树
/**
* 连接数据库什么的
*/
function __construct()
{
$this->db = new mysqli('localhost', 'root', '245030109', 'test');
}

/**
* 根据id获取整棵树
* @param int $id
* @return array|flase
*/
function getTreeByRootID($id)
{
$query = "select lft,rgt from nestedCategory where id = $id";
$res   = $this->db->query($query);
if($res->num_rows<=0){ //查找的根节点树不在
return false;
}
$row = $res->fetch_assoc();
$lft = $row['lft']; //获取左值
$rgt = $row['rgt']; //获取右值
$arrayRight = array(); //记录每个节点的又值便于分出父子关系

$query = "select * from nestedCategory where lft>=$lft and rgt <= $rgt order by lft ";
$res   = $this->db->query($query);
for($i=0;$i<$res->num_rows;$i++){
$row = $res->fetch_assoc();

while(!empty($arrayRight)&&end($arrayRight)<$row['rgt']){ //相邻的两条记录的右值第一条的右值比第二条的大那么就是他的父类
//不是父类出栈
array_pop($arrayRight);
}

$tiltle = $row['title'];
if(!empty($arrayRight)){
//$tiltle = '|-'.$tiltle;
}

//这里设置节点在树中的层数没有- 表示 根节点
$this->tree[] = array('title'=>str_repeat('-', count($arrayRight)).$tiltle);
$arrayRight[] = $row['rgt'];
}
return $this->tree;
}

/**
* 为某个父节点添加一个子节点
* //这里一般创建存储过程
* @param int $parentId
* @param int $selfId
* @param string $title
*/
function addNodeByPid($parentId,$selfId,$title='default')
{
$query = "select lft from nestedCategory where id = $parentId";
$res   = $this->db->query($query);
if($res->num_rows<=0){
return false;
}
$row   = $res->fetch_assoc();
$lft   = $row['lft'];

//更新左值大于该父节点左值的值
$query = "update nestedCategory set lft = lft+ 2 where lft>$lft";
$res = $this->db->query($query);
if(!$res){
return false;
}

//更新右值大于该父节点左值的值
$query = "update nestedCategory set rgt = rgt+ 2 where rgt>$lft";
$res   = $this->db->query($query);
if(!$res){
return false;
}

//插入节点
$query = "insert into nestedCategory values($selfId,'".$title."',".($lft+1).','.($lft+2).')';
$res   = $this->db->query($query);
if(!$res){
return FALSE;
}
return true;
}

/**
* 删除一棵树
* @param int $id
*/
function deleteNodeById($id)
{
//
$query = "select lft,rgt from nestedCategory where id = $id ";
$res   = $this->db->query($query);
if($res->num_rows<=0){
return false;
}
$row   = $res->fetch_assoc();
$dis   = $row['rgt']-$row['lft']+1;

//删除树
$query = "delete from nestedCategory where lft>=".$row['lft']." and lft<=".$row['rgt']; //删除左值在lft和rgt之间的结点,包括自己
$res   = $this->db->query($query);
if(!$res){
return false;
}

//更新其他结点
$query = "update nestedCategory set lft=lft-$dis where lft>".$row['rgt'];//更新左值
$res   = $this->db->query($query);
if(!$res){
return false;
}

$query = "update nestedCategory set rgt=rgt-$dis where rgt>".$row['rgt'];//更新右值
$res   = $this->db->query($query);
if(!$res){
return false;
}
return true;
}

/**
* 输出树形结构
* @param array $arrayList
*/
function displayTree(array $arrayList)
{
foreach ($arrayList as $list){
if(is_array($list)){
foreach ($list as $val){
echo $val,'<br/>';
}
}else{
echo $list,'<br/>';
}
}
}
}
?>


调用文件:

<?php
require_once 'nestedCategory.php';
$nest = new nestedCategory();

$arrList = $nest->getTreeByRootID(1);

$nest->displayTree($arrList);

$nest->addNodeByPid(1, 10,'addnode1');
$nest->addNodeByPid(1, 11,'addnode2');
$arrList = $nest->getTreeByRootID(1);
$nest->displayTree($arrList);
$nest->deleteNodeById(2);
?>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: