做网站的时候有时需要实现一个树形列表,类似目录那样的。最好的建立方法就是采用指向父节点的指针的结构建立表。
表的结构如下:(表名为xx)
字段 | 类型 | Null | 默认 | 注释 |
CId | int(11) | 否 |
| 主键 |
PId | int(11) | 否 | 0 | 父类别的CId,=0表示该项为顶层类别。 |
Name | varchar(64) | 否 |
| 类别名。 |
查询时只需要一个SQL语句就能查询出所有节点:
select distinct c2.CId, c2.PId, c2.Name
from xx c1, xx c2
where c2.PId=c1.CId or c2.PId=0;
这样查询出来的结果就是一个链式存储的,指向父节点指针的树了,现在我们要做的就是把这棵树变成普通的树,这样我们就可以方便的输出了。
下面是用PHP实现的转换代码:
查询出来的结果存在 $this->data 里,格式如下:
Array
(
[0] => Array ( [CId] => 1, [PId] => 0, [Name] => 运动 )
[1] => Array ( [CId] => 2, [PId] => 0, [Name] => 游戏 )
[2] => Array ( [CId] => 3, [PId] => 0, [Name] => 程序 )
[3] => Array ( [CId] => 4, [PId] => 1, [Name] => 足球 )
[4] => Array ( [CId] => 5, [PId] => 1, [Name] => 篮球 )
[5] => Array ( [CId] => 6 [PId] => 1 [Name] => 羽毛球 )
[6] => Array ( [CId] => 7 [PId] => 2 [Name] => 即时战略类 )
[7] => Array ( [CId] => 8 [PId] => 2 [Name] => RPG类 )
[8] => Array ( [CId] => 9 [PId] => 7 [Name] => 红警 )
[9] => Array ( [CId] => 10 [PId] => 7 [Name] => 星际 )
[10] => Array ( [CId] => 11 [PId] => 7 [Name] => 魔兽 )
[11] => Array ( [CId] => 12 [PId] => 8 [Name] => 仙剑 )
)
<?php
// 测试输出,把结果输出成嵌套的<ul>
// 采用先根遍历进行输出。
function preorder($tree, $data)
{
foreach ($tree as $k => $v) {
if ($k) // 不输出总根
echo '<li>'.$data[$k]['Name'].'('.
$data[$k]['CId'].') »';
if (sizeof($v)>0) {
echo '<ul>';
preorder($v, $data);
echo "</ul>/n";
}
echo "</li>/n";
}
}
/**
* 在当前节点处递归建立树。
*
* @param $tree array, 当前节点。
* @param $pa array, 祖先节点表,老的排前面。
* @param $i int, $pa的当前位置。
* @param $n int, 要插入的节点。
*
* @return void
*/
function create_tree(& $tree, $pa, $i, $n)
{
if (sizeof($pa)==$i) {
// 到达最底层祖先节点(即要插入节点的直接父节点)
// 插入当前节点
$tree[$n]=array();
return;
}
// 递归到下一级祖先处
$next=$pa[$i];
create_tree($tree[$next], $pa, $i+1, $n);
}
$plist=array();
$list[0]=array();
// 重排数据库查询结果,使得$data的下标即为$CId。
// 并生成树,存入$list中($list[0])为数的根节点。
foreach ($this->data as $v) {
$cid=$v['CId'];
$pid=$v['PId'];
$plist[$cid]=array($pid); // $plist[i]为i的祖先链
$data[$cid]=array('CId'=>$cid, 'PId'=>$pid, 'Name'=>$v['Name']);
if ($pid) // 如果其父节点不为根,则继承父的祖先
$plist[$cid]=array_merge($plist[$pid], $plist[$cid]);
create_tree($list, $plist[$cid], 0, $cid); // 递归建立树
}
preorder($list, $data);
?>
调用完create_tree以后,$list 里是这样的:
Array
(
[0] => Array
(
[1] => Array
(
[4] => Array ( )
[5] => Array ( )
[6] => Array ( )
)
[2] => Array
(
[7] => Array
(
[9] => Array ( )
[10] => Array ( )
[11] => Array ( )
)
[8] => Array
(
[12] => Array ( )
)
)
[3] => Array ( )
)
)
输出结果:(后面数字是它的CId)
- 运动(1) »
- 足球(4) »
- 篮球(5) »
- 羽毛球(6) »
- 游戏(2) »
- 即时战略类(7) »
- 红警(9) »
- 星际(10) »
- 魔兽(11) »
- RPG类(8) »
- 仙剑(12) »
- 即时战略类(7) »
- 程序(3) »
没怎么整理,等有时间了再好好整理一下。