PHP无限级分类实现:递归与迭代法构建子孙树与家谱树
在处理后台管理、内容发布或目录导航等系统时,无限级分类是常见的数据结构需求。本文将探讨如何在 PHP 中通过数组处理无限级分类数据,分别演示利用递归构建深层级的子孙树,以及使用递归和迭代两种方式向上追溯的家谱树(路径回溯),帮助开发者理解不同场景下的算法选择。
结果与目标
在本地开发或数据处理阶段,我们通常面临将扁平的二维数组转换为具有层级关系的一维结构(用于下拉框或列表展示),或者需要根据当前节点ID反向获取其所有父级节点(用于面包屑导航)的需求。以下案例均基于同一组区域数据进行演示。
准备条件
假设数据库中有一张地区表,我们在 PHP 内存中将其加载为二维数组。parent 字段存储父级节点的 ID,0 表示顶级节点。数据结构如下:
$area = array(
array('id'=>1,'name'=>'安徽','parent'=>0),
array('id'=>2,'name'=>'海淀','parent'=>7),
array('id'=>3,'name'=>'濉溪县','parent'=>5),
array('id'=>4,'name'=>'昌平','parent'=>7),
array('id'=>5,'name'=>'淮北','parent'=>1),
array('id'=>6,'name'=>'朝阳','parent'=>7),
array('id'=>7,'name'=>'北京','parent'=>0),
array('id'=>8,'name'=>'上地','parent'=>2)
);
真实操作顺序
第1步:利用递归查找子孙树
目的:将所有指定根节点下的子节点按层级展开成单一的一维数组,常用于生成无限级下拉菜单或前端树形组件的数据源。
入口参数:$arr(数据源数组),$id(起始查找ID,默认为0即从根开始),$lev(当前层级深度)。
function subtree($arr,$id=0,$lev=1) {
$subs = array(); // 子孙数组
foreach($arr as $v) {
if($v['parent'] == $id) {
$v['lev'] = $lev;
$subs[] = $v; // 找到直接子节点
$subs = array_merge($subs,subtree($arr,$v['id'],$lev+1)); // 递归继续查找下级
}
}
return $subs;
}
$tree = subtree($area,0,1);
foreach($tree as $v) {
echo str_repeat(' ',$v['lev']),$v['name'],'<br />';
}
完成状态:执行后得到包含所有后代节点且带有 lev 属性标识层级的新数组,打印输出即为层级缩进效果。
第2步:利用递归求家谱树(路径回溯)
目的:给定任意一个节点 ID,获取从该节点到最顶级祖先节点的所有路径信息。此方法常用于渲染“首页 > 分类 > 子类”的面包屑导航。
function familytree($arr,$id) {
$tree = array();
foreach($arr as $v) {
if($v['id'] == $id) {
if($v['parent'] > 0) { // parent>0说明还有上级
$tree = array_merge($tree,familytree($arr,$v['parent']));
}
$tree[] = $v;
}
}
return $tree;
}
print_r(familytree($area,8)); // 预期输出: 北京-海淀-上地
注意:递归虽然逻辑直观,但如果分类层级极深,可能会消耗较多栈内存。
第3步:利用迭代求家谱树(推荐高效方案)
目的:在不牺牲代码可读性的前提下,避免递归带来的调用开销,适合层级较深的场景。
// 迭代方式找家谱树
function tree($arr,$id) {
$tree = array();
while($id !== 0) {
foreach($arr as $v) {
if($v['id'] == $id) {
$tree[] = $v;
$id = $v['parent'];
break;
}
}
}
return $tree;
}
print_r(tree($area,8));
关键区别:使用 while 循环不断定位当前 ID 的父亲节点,直到父亲 ID 为 0 为止。这种方法效率更高,代码逻辑同样清晰。
简要总结
以上就是PHP实现无限级分类并生成子孙树与家谱树的详细内容,更多关于PHP数据结构和算法优化的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













