用数据库实现树型结构

做网站的时候有时需要实现一个树形列表,类似目录那样的。最好的建立方法就是采用指向父节点的指针的结构建立表。
表的结构如下:(表名为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'].') &raquo;';
        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) »
  • 程序(3) »


没怎么整理,等有时间了再好好整理一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值