无限分类在日常开发中很常见至少对于PHP程序员来说,如网站常见的商品分类、面包屑、省市联动、新闻分类等等,一个栏目又包含很多个子栏目子栏目又包含很多子栏目...。 这里介绍无限分类的子孙树与家谱树实现。
子孙树是用递归查找栏目的所有子类,以及子类的子类,子类的子类的子类。
1.数据准备
$arr = [
['id'=>1,'name'=>'四川','parent'=>0],
['id'=>2,'name'=>'广东','parent'=>0],
['id'=>3,'name'=>'成都','parent'=>1],
['id'=>4,'name'=>'德阳','parent'=>1],
['id'=>5,'name'=>'南充','parent'=>1],
['id'=>6,'name'=>'深圳','parent'=>2],
['id'=>7,'name'=>'华阳县','parent'=>3],
['id'=>8,'name'=>'金牛区','parent'=>3],
['id'=>9,'name'=>'营山县','parent'=>5],
['id'=>10,'name'=>'嘉陵区','parent'=>5],
['id'=>11,'name'=>'南部县','parent'=>5],
['id'=>12,'name'=>'罗江区','parent'=>4],
['id'=>13,'name'=>'旌阳区','parent'=>4],
['id'=>14,'name'=>'南山区','parent'=>6],
['id'=>15,'name'=>'盐田区','parent'=>6],
['id'=>16,'name'=>'星火镇','parent'=>9],
['id'=>17,'name'=>'七涧乡','parent'=>16],
];
我们将所有地区都放在一个数组,他们之间的关系依靠parent
绑定,顶级的地区parent
等于0 案例:查找某地区以及该地区管辖的子地区
function subtree($arr,$id){
static $subs = [];
foreach($arr as $v){
//查找一级
if($v['parent']==$id){
$subs[] = $v;
subtree($arr,$v['id']);
}
}
return $subs;
}
print_r(subtree($arr,1));
结果如下
Array
(
[0] => Array
(
[id] => 3
[name] => 成都
[parent] => 1
)
[1] => Array
(
[id] => 7
[name] => 华阳县
[parent] => 3
)
[2] => Array
(
[id] => 8
[name] => 金牛区
[parent] => 3
)
[3] => Array
(
[id] => 4
[name] => 德阳
[parent] => 1
)
[4] => Array
(
[id] => 12
[name] => 罗江区
[parent] => 4
)
[5] => Array
(
[id] => 13
[name] => 旌阳区
[parent] => 4
)
[6] => Array
(
[id] => 5
[name] => 南充
[parent] => 1
)
[7] => Array
(
[id] => 9
[name] => 营山县
[parent] => 5
)
[8] => Array
(
[id] => 16
[name] => 星火镇
[parent] => 9
)
[9] => Array
(
[id] => 17
[name] => 七涧乡
[parent] => 16
)
[10] => Array
(
[id] => 10
[name] => 嘉陵区
[parent] => 5
)
[11] => Array
(
[id] => 11
[name] => 南部县
[parent] => 5
)
)
所有地区被打印出来,并且正常分类,我们还可以将其格式输出只需要给某个地区添加级别标识即可
function subtree($arr,$id,$lev=1){
static $subs = [];
foreach($arr as $v){
//查找一级
if($v['parent']==$id){
$v['lev'] = $lev;
$subs[] = $v;
subtree($arr,$v['id'],$lev+1);
}
}
return $subs;
}
$tree = subtree($arr,1);
foreach ($tree as $v) {
echo str_repeat('----',$v['lev']).$v['name']."<br />";
}
输出如下
----成都
--------华阳县
--------金牛区
----德阳
--------罗江区
--------旌阳区
----南充
--------营山县
------------星火镇
----------------七涧乡
--------嘉陵区
--------南部县
家谱树利用递归查找子栏目的父级栏目,父级栏目的父级栏目,父级栏目的父级栏目的父级栏目... 家谱树的应用也很广泛如常见的面包屑导航
案例:查找某地区的父栏目的栏目的父栏目....
function basetree($arr,$id){
static $fathers = [];
foreach ($arr as $v) {
if($v['id']==$id){
//判断是否继续寻找父栏目
if($v['parent']>0){
basetree($arr,$v['parent']);
}
$fathers[] = $v;
}
}
return $fathers;
}
print_r(basetree($arr,16));
返回结果
Array
(
[0] => Array
(
[id] => 1
[name] => 四川
[parent] => 0
)
[1] => Array
(
[id] => 5
[name] => 南充
[parent] => 1
)
[2] => Array
(
[id] => 9
[name] => 营山县
[parent] => 5
)
[3] => Array
(
[id] => 16
[name] => 星火镇
[parent] => 9
)
)
迭代家谱树
function basetree($arr,$id){
$fathers = [];
while ($id!=0) {
foreach ($arr as $v) {
if($v['id']==$id){
$fathers[] = $v;
$id = $v['parent'];
break;
}
}
}
return $fathers;
}
print_r(basetree($arr,16));
返回结果与上面一样不过性能比递归要高