php:树形结构的算法2
2008-05-01 04:57
633 查看
.Ucg461{display:none;} 1Food18
|
+---------------------------------------+
||
2Fruit1112Meat17
||
+------------------------++---------------------+
||||
3Red67Yellow1013Beef1415Pork16
||
4Cherry58Banana9
这样整个树状结构可以通过左右值来存储到数据库中。继续之前,我们看一看下面整理过的数据表。
+-----------------------+-----+-----+
|parent|name|lft|rgt|
+-----------------------+-----+-----+
||Food|1|18|
|Food|Fruit|2|11|
|Fruit|Red|3|6|
|Red|Cherry|4|5|
|Fruit|Yellow|7|10|
|Yellow|Banana|8|9|
|Food|Meat|12|17|
|Meat|Beef|13|14|
|Meat|Pork|15|16|
+-----------------------+-----+-----+
注意:由于"left"和"right"在SQL中有特殊的意义,所以我们需要用"lft"和"rgt"来表示左右字段。另外这种结构中不再需要"parent"字段来表示树状结构。也就是说下面这样的表结构就足够了。
+------------+-----+-----+
|name|lft|rgt|
+------------+-----+-----+
|Food|1|18|
|Fruit|2|11|
|Red|3|6|
|Cherry|4|5|
|Yellow|7|10|
|Banana|8|9|
|Meat|12|17|
|Beef|13|14|
|Pork|15|16|
+------------+-----+-----+
好了我们现在可以从数据库中获取数据了,例如我们需要得到"Fruit"项下的所有所有节点就可以这样写查询语句:SELECT*FROMtreeWHERElftBETWEEN2AND11;这个查询得到了以下的结果。
+------------+-----+-----+
|name|lft|rgt|
+------------+-----+-----+
|Fruit|2|11|
|Red|3|6|
|Cherry|4|5|
|Yellow|7|10|
|Banana|8|9|
+------------+-----+-----+
看到了吧,只要一个查询就可以得到所有这些节点。为了能够像上面的递归函数那样显示整个树状结构,我们还需要对这样的查询进行排序。用节点的左值进行排序:
SELECT*FROMtreeWHERElftBETWEEN2AND11ORDERBYlftASC;
剩下的问题如何显示层级的缩进了。
<?php
functiondisplay_tree($root)
{
//得到根节点的左右值
$result=mysql_query('SELECTlft,rgtFROMtree'.'WHEREname="'.$root.'";');
$row=mysql_fetch_array($result);
//准备一个空的右值堆栈
$right=array();
//获得根基点的所有子孙节点
$result=mysql_query('SELECTname,lft,rgtFROMtree'.
'WHERElftBETWEEN'.$row['lft'].'AND'.
$row['rgt'].'ORDERBYlftASC;');
//显示每一行
while($row=mysql_fetch_array($result))
{
//onlycheckstackifthereisone
if(count($right)>0)
{
//检查我们是否应该将节点移出堆栈
while($right[count($right)-1]<$row['rgt'])
{
array_pop($right);
}
}
//缩进显示节点的名称
echostr_repeat('',count($right)).$row['name']."n";
//将这个节点加入到堆栈中
$right[]=$row['rgt'];
}
}
?>
如果你运行一下以上的函数就会得到和递归函数一样的结果。只是我们的这个新的函数可能会更快一些,因为只有2次数据库查询。要获知一个节点的路径就更简单了,如果我们想知道Cherry的路径就利用它的左右值4和5来做一个查询。
SELECTnameFROMtreeWHERElft<4ANDrgt>5ORDERBYlftASC;
这样就会得到以下的结果:
+------------+
|name|
+------------+
|Food|
|Fruit|
|Red|
+------------+
那么某个节点到底有多少子孙节点呢?很简单,子孙总数=(右值-左值-1)/2descendants=(right–left-1)/2不相信?自己算一算啦。用这个简单的公式,我们可以很快的算出"Fruit2-11"节点有4个子孙节点,而"Banana8-9"节点没有子孙节点,也就是说它不是一个父节点了。
很神奇吧?虽然我已经多次用过这个方法,但是每次这样做的时候还是感到很神奇。
这的确是个很好的办法,但是有什么办法能够帮我们建立这样有左右值的数据表呢?这里再介绍一个函数给大家,这个函数可以将name和parent结构的表自动转换成带有左右值的数据表。
<?php
functionrebuild_tree($parent,$left){
//therightvalueofthisnodeistheleftvalue+1
$right=$left+1;
//getallchildrenofthisnode
$result=mysql_query('SELECTnameFROMtree'.
'WHEREparent="'.$parent.'";');
while($row=mysql_fetch_array($result)){
//recursiveexecutionofthisfunctionforeach
//childofthisnode
//$rightisthecurrentrightvalue,whichis
//incrementedbytherebuild_treefunction
$right=rebuild_tree($row['name'],$right);
}
//we'vegottheleftvalue,andnowthatwe'veprocessed
//thechildrenofthisnodewealsoknowtherightvalue
mysql_query('UPDATEtreeSETlft='.$left.',rgt='.
$right.'WHEREname="'.$parent.'";');
//returntherightvalueofthisnode+1
return$right+1;
}
?>
当然这个函数是一个递归函数,我们需要从根节点开始运行这个函数来重建一个带有左右值的树
rebuild_tree('Food',1);
这个函数看上去有些复杂,但是它的作用和手工对表进行编号一样,就是将立体多层结构的转换成一个带有左右值的数据表。
|
+---------------------------------------+
||
2Fruit1112Meat17
||
+------------------------++---------------------+
||||
3Red67Yellow1013Beef1415Pork16
||
4Cherry58Banana9
这样整个树状结构可以通过左右值来存储到数据库中。继续之前,我们看一看下面整理过的数据表。
+-----------------------+-----+-----+
|parent|name|lft|rgt|
+-----------------------+-----+-----+
||Food|1|18|
|Food|Fruit|2|11|
|Fruit|Red|3|6|
|Red|Cherry|4|5|
|Fruit|Yellow|7|10|
|Yellow|Banana|8|9|
|Food|Meat|12|17|
|Meat|Beef|13|14|
|Meat|Pork|15|16|
+-----------------------+-----+-----+
注意:由于"left"和"right"在SQL中有特殊的意义,所以我们需要用"lft"和"rgt"来表示左右字段。另外这种结构中不再需要"parent"字段来表示树状结构。也就是说下面这样的表结构就足够了。
+------------+-----+-----+
|name|lft|rgt|
+------------+-----+-----+
|Food|1|18|
|Fruit|2|11|
|Red|3|6|
|Cherry|4|5|
|Yellow|7|10|
|Banana|8|9|
|Meat|12|17|
|Beef|13|14|
|Pork|15|16|
+------------+-----+-----+
好了我们现在可以从数据库中获取数据了,例如我们需要得到"Fruit"项下的所有所有节点就可以这样写查询语句:SELECT*FROMtreeWHERElftBETWEEN2AND11;这个查询得到了以下的结果。
+------------+-----+-----+
|name|lft|rgt|
+------------+-----+-----+
|Fruit|2|11|
|Red|3|6|
|Cherry|4|5|
|Yellow|7|10|
|Banana|8|9|
+------------+-----+-----+
看到了吧,只要一个查询就可以得到所有这些节点。为了能够像上面的递归函数那样显示整个树状结构,我们还需要对这样的查询进行排序。用节点的左值进行排序:
SELECT*FROMtreeWHERElftBETWEEN2AND11ORDERBYlftASC;
剩下的问题如何显示层级的缩进了。
<?php
functiondisplay_tree($root)
{
//得到根节点的左右值
$result=mysql_query('SELECTlft,rgtFROMtree'.'WHEREname="'.$root.'";');
$row=mysql_fetch_array($result);
//准备一个空的右值堆栈
$right=array();
//获得根基点的所有子孙节点
$result=mysql_query('SELECTname,lft,rgtFROMtree'.
'WHERElftBETWEEN'.$row['lft'].'AND'.
$row['rgt'].'ORDERBYlftASC;');
//显示每一行
while($row=mysql_fetch_array($result))
{
//onlycheckstackifthereisone
if(count($right)>0)
{
//检查我们是否应该将节点移出堆栈
while($right[count($right)-1]<$row['rgt'])
{
array_pop($right);
}
}
//缩进显示节点的名称
echostr_repeat('',count($right)).$row['name']."n";
//将这个节点加入到堆栈中
$right[]=$row['rgt'];
}
}
?>
如果你运行一下以上的函数就会得到和递归函数一样的结果。只是我们的这个新的函数可能会更快一些,因为只有2次数据库查询。要获知一个节点的路径就更简单了,如果我们想知道Cherry的路径就利用它的左右值4和5来做一个查询。
SELECTnameFROMtreeWHERElft<4ANDrgt>5ORDERBYlftASC;
这样就会得到以下的结果:
+------------+
|name|
+------------+
|Food|
|Fruit|
|Red|
+------------+
那么某个节点到底有多少子孙节点呢?很简单,子孙总数=(右值-左值-1)/2descendants=(right–left-1)/2不相信?自己算一算啦。用这个简单的公式,我们可以很快的算出"Fruit2-11"节点有4个子孙节点,而"Banana8-9"节点没有子孙节点,也就是说它不是一个父节点了。
很神奇吧?虽然我已经多次用过这个方法,但是每次这样做的时候还是感到很神奇。
这的确是个很好的办法,但是有什么办法能够帮我们建立这样有左右值的数据表呢?这里再介绍一个函数给大家,这个函数可以将name和parent结构的表自动转换成带有左右值的数据表。
<?php
functionrebuild_tree($parent,$left){
//therightvalueofthisnodeistheleftvalue+1
$right=$left+1;
//getallchildrenofthisnode
$result=mysql_query('SELECTnameFROMtree'.
'WHEREparent="'.$parent.'";');
while($row=mysql_fetch_array($result)){
//recursiveexecutionofthisfunctionforeach
//childofthisnode
//$rightisthecurrentrightvalue,whichis
//incrementedbytherebuild_treefunction
$right=rebuild_tree($row['name'],$right);
}
//we'vegottheleftvalue,andnowthatwe'veprocessed
//thechildrenofthisnodewealsoknowtherightvalue
mysql_query('UPDATEtreeSETlft='.$left.',rgt='.
$right.'WHEREname="'.$parent.'";');
//returntherightvalueofthisnode+1
return$right+1;
}
?>
当然这个函数是一个递归函数,我们需要从根节点开始运行这个函数来重建一个带有左右值的树
rebuild_tree('Food',1);
这个函数看上去有些复杂,但是它的作用和手工对表进行编号一样,就是将立体多层结构的转换成一个带有左右值的数据表。
相关文章推荐
- php:树形结构的算法1
- php:树形结构的算法
- php:树形结构的算法
- php:树形结构的算法1
- php:树形结构的算法 2
- php:树形结构的算法
- php:树形结构的算法3
- php:树形结构的算法4
- php+jquery读取文件目录生成树形结构
- php当数据量不是很大的时候,使用【递归循环出树形结构】的一个用户下面的所有人
- How to print a tree-ADT ? 打印树形结构的算法
- 自定义php通用树形结构类
- 将树形结构的数据转换为二维数组 (续 PHP非递归方式实现无限分类(转载))
- 【数据结构与算法学习笔记】PART4 树形结构(二叉树,堆)
- 数据结构与算法之递推算法 C++与PHP实现
- 编程珠玑 - 算法优化 - 过滤敏感词 - 第三步:树形结构
- java树形结构 算法
- java树形结构 两种算法
- Go语言实现的树形结构数据比较算法实例
- php树形结构数据排序算法