树形结构问题的一种解决办法

在一个标准的树形结构里面,一般要想知道的操作基本上有查询子树和查询所有父树(路径),还有就是查询子树自身的深度问题,通过前些日子的总结发现一种结构可以很好的满足这些要求。
id parentID   name        path
———————————-
1     0              图书          0,1
2     1      
      管理类       0,1,2
3     2      
     名家作品     0,1,2,3
4     2      
     国内          0,1,2,4
5     2      
     外国          0,1,2,5
6     0      
     文学类       0,6
7     6      
     小说          0,6,7

上面这种结构就是我推荐的,这种结构对于我们通常用的id-parentID结构增加了一个路径(path)列,好处就是可以直接通过查询path列来找 出某个节点的子树和路径,比如2号节点的子树可以通过先查2号子树的path,然后再用like ‘0,1,2%’方式来得到。其路径可以通过in(0,1,2)查询到。深度可以通过explode(‘,’,$path),然后看看数组个数就可以看出 节点的深度了,这样就可以构建出一个树形结构了。
path列的构建可以在原有id-parentID结构上增加,通过id和parentid可以很方便的构建出某个节点的子树的path列(需要递归算法)。
常用的函数可以有三个:
nav($node) 根据节点求出其路径,先找出节点path然后根据path用"select * from category where id in ($path)",就能求出其路径所有节点了,方便导航。
tree($node)根据节点求出其所有子树,先找出节点path,然后用"select * from category where path like ‘$path%’",就可以找出所有子节点啦,这里可以通过计算每个节点的path中有几个元素explode(‘,’$path)计算每个节点的深度。
re_path($node)根据节点,重新构建子树的path,这个需要利用ID和ParentID两列,利用递归逐步计算,因为只有在改变子树隶属关系和建立新节点的时候用到,所以计算量应该不是很多。
好了上面是这种算法的基本构想,大家有什么新的构想,提出来讨论一下。

“改进前序遍历树”方法,这里有相关中文翻译介绍,http://www.nirvanastudio.org/category/database/
我这里提的方法很像“邻接列表模型”,就是增加了一个path列,所以针对邻接列表模型所遇到的最大的问题,子树、路径和深度问题得到了改善。
而改进前序遍历树方法也是有很大的局限的,就是当某个节点变换父节点时需要做大量的修改左右数值。而上面的方法修改量要小一点!
不知道这么说是否妥当,请指教!

附常用的三个函数:
function nav($id,$db){
$rs=$db->query("select * from category where id=’".$id."’");
$row=$rs->fetch();
$rs=$db->query("select * from category where id in (".$row[‘path’].") order by path");
return $rs->fetchall();
}
function tree($id,$db){
$rs=$db->query("select * from category where id=’".$id."’");
$row=$rs->fetch();
$rs=$db->query("select * from category where path like ‘".$row[‘path’]."%’ order by path");
$tree=$rs->fetchall();
foreach($tree as $key=>$row){
$depth=explode(‘,’,$row[‘path’]);
$depth=count($depth);
$tree[$key][‘depth’]=$depth;
}
return $tree;
}

function re_path($id,$parentpath=”,$db){//此函数使用前需要先获得父节点的path
       if($parentpath<>”){$path=$parentpath.’,’.$id;}else{$path=$id;}
$sql="update category set path=’".$path."’ where id=’"$id"’";
$rs=$db->query($sql);

$sql="select * from category where parentid=’".$id."’";
$rs=$db->query($sql);
while($row=$rs->fetch()){
   re_path($row[‘id’],$path,$db);
}
}

Read: 878

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注