存储树状结构(上)─领接表方式

我们经常需要在关系型数据库中保存一些树状结构数据,比如分类、分组、权限控制 ACL、论坛帖子树状回复等等。常用的方法有两种,一种是领接表的方式,另一种是预排序遍历树方式。

本文以 MySQL 和 PHP 为例进行说明,假设树状结构如下:
树结构图 

领接表方式

领接表方式主要依赖于一个 parent 字段,用于指向上级节点,将相邻的上下级节点连接起来,从而将整个树的各个节点连接起来。这样,我们例子中的节点变成行记录如下:
数据库结构
id 为自动递增自动,parent_id 为上级节点的 id。一目了然,“PHP”是“Language”的子节点。

接下来我们要显示树,PHP 代码也可以很直观,显示树的子节点的代码如下:


<?php
/**
 * @param $parent_id 父节点 id,0 则显示整个树结构。
 * @param $level 当前节点所处的层级,用于缩进显示节点。
 */
function show_children($parent_id 0$level 0)
{
    // 获取父节点下的所有子节点
    $result mysql_query('SELECT id, name FROM tree WHERE parent_id='.intval($parent_id));
    // 显示每个子节点
    while ($row mysql_fetch_array($result)) {
        // 缩进显示
        echo '<div style="margin-left:'.($level*12).'px">'.$row['name'].'</div>';
        // 递归调用当前函数,显示再下一级的子节点
        show_children($row['id'], $level+1);
    }
}
?>

想要显示整个树结构,调用 show_children()。想要显示“Database”子树,则调用 show_children(2),因为“Database”的 id 是 2。

还有一个经常用到的功能是获取节点路径,即给出一个节点,返回从根节点到当前节点的路径。用函数实现如下:


<?php
/**
 * @param $id 需要获取路径的当前节点的 id。
 */
function get_path($id) 
{
    // 获取当前节点的父节点 id 和当前节点名
    $result mysql_query('SELECT parent_id, name FROM tree WHERE id='.intval($id));
    $row mysql_fetch_array($result);
    // 使用此数组保存路径
    $path = array();
    // 将当前节点名保存进路径数组中
    $path[] = $row['name'];
    // 如果父节点非 0,即非根节点,则进行递归调用获取父节点的路径
    if ($row['parent_id']) {
        // 递归调用,获取父节点的路径,并且合并到当前路径数组的其它元素前边
        $path array_merge(get_path($row['parent_id']), $path);
    }
    return $path;
}
?>

想要获取“MySQL 5.0”的路径,调用 get_path(4),4 即是这个节点的 id。

领接表方式的优点在于容易理解,代码也比较简单明了。缺点则是递归中的 SQL 查询会导致负载变大,特别是需要处理比较大型的树状结构的时候,查询语句会随着层级的增加而增加,WEB 应用的瓶颈基本都在数据库方面,所以这是一个比较致命的缺点,直接导致树结构的扩展困难重重。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值