php递归有限分类,PHP实现无限级分类(不使用递归)

在进行无限极分类中最常用的算法就是“递归”,熟悉PHP语言的朋友肯定知道,PHP不擅长递归 ,而且递归次数有限(100次左右,因操作系统和配置而异)。

所以本文将会给大家带来几种不使用递归实现无限级分类的代码。供大家来学习使用。

第一种:

无限级分类在开发中经常使用,例如:部门结构、文章分类。无限级分类的难点在于“输出”和“查询”,例如将文章分类输出为

  • 列表形式;

查找分类A下面所有分类包含的文章。

1.实现原理

几种常见的实现方法,各有利弊。其中“改进前序遍历树”数据结构,便于输出和查询,但是在移动分类和常规理解上有些复杂。

2.数据结构

c43c818121262bda0bb7b2665bbeec5a.png<?php

$list = array(

array('id'=>1, 'fid'=>0, 'title' => '中国'),

array('id'=>2, 'fid'=>1, 'title' => '江苏'),

array('id'=>3, 'fid'=>1, 'title' => '安徽'),

array('id'=>4, 'fid'=>8, 'title' => '江阴'),

array('id'=>5, 'fid'=>3, 'title' => '芜湖'),

array('id'=>6, 'fid'=>3, 'title' => '合肥'),

array('id'=>7, 'fid'=>3, 'title' => '蚌埠'),

array('id'=>8, 'fid'=>8, 'title' => '无锡')

);

?>

由于所有的递归均可以使用循环实现,本文根据PHP语言特点编写了一套关于“无限级”分类的函数,相比递归实现而言效率更高。

3.输出ul列表形式

将上述数据输出为下面的HTML

  • 江苏

    • 无锡

      • 江阴

  • 安徽

    • 芜湖

    • 合肥

    • 蚌埠

这种HTML结构在前端使用(使用JavaScript和CSS构造可折叠树)十分方便。具体实现程序如下:

4.输出option列表形式

江苏

无锡

江阴

安徽

芜湖

合肥

蚌埠

具体实现程序如下:

// get_tree_option()返回数组,并为每个元素增加了“深度”(即depth)列,直接输出即可

$options = get_tree_option($list, 1);

foreach($options as $op) {

echo '' . str_repeat(" ", $op['depth'] * 4) . $op['title'] . '';

}

?>

5. 查找某一分类的所有子类<?php

$children = get_tree_child($list, 0);

echo implode(',', $children); // 输出:1,3,2,7,6,5,8,4

?>

6. 查找某一分类的所有父类<?php

$children = get_tree_parent($list, 4);

echo implode(',', $children); //8, 2, 10

?>

7. 相关函数<?php

function get_tree_child($data, $fid) {

$result = array();

$fids = array($fid);

do {

$cids = array();

$flag = false;

foreach($fids as $fid) {

for($i = count($data) - 1; $i >=0 ; $i--) {

$node = $data[$i];

if($node['fid'] == $fid) {

array_splice($data, $i , 1);

$result[] = $node['id'];

$cids[] = $node['id'];

$flag = true;

}

}

}

$fids = $cids;

} while($flag === true);

return $result;

}

function get_tree_parent($data, $id) {

$result = array();

$obj = array();

foreach($data as $node) {

$obj[$node['id']] = $node;

}

$value = isset($obj[$id]) ? $obj[$id] : null;

while($value) {

$id = null;

foreach($data as $node) {

if($node['id'] == $value['fid']) {

$id = $node['id'];

$result[] = $node['id'];

break;

}

}

if($id === null) {

$result[] = $value['fid'];

}

$value = isset($obj[$id]) ? $obj[$id] : null;

}

unset($obj);

return $result;

}

function get_tree_ul($data, $fid) {

$stack = array($fid);

$child = array();

$added_left = array();

$added_right= array();

$html_left = array();

$html_right = array();

$obj = array();

$loop = 0;

foreach($data as $node) {

$pid = $node['fid'];

if(!isset($child[$pid])) {

$child[$pid] = array();

}

array_push($child[$pid], $node['id']);

$obj[$node['id']] = $node;

}

while (count($stack) > 0) {

$id = $stack[0];

$flag = false;

$node = isset($obj[$id]) ? $obj[$id] : null;

if (isset($child[$id])) {

$cids = $child[$id];

$length = count($cids);

for($i = $length - 1; $i >= 0; $i--) {

array_unshift($stack, $cids[$i]);

}

$obj[$cids[$length - 1]]['isLastChild'] = true;

$obj[$cids[0]]['isFirstChild'] = true;

$flag = true;

}

if ($id != $fid && $node && !isset($added_left[$id])) {

if(isset($node['isFirstChild']) && isset($node['isLastChild'])) {

$html_left[] = '

';

} else if(isset($node['isFirstChild'])) {

$html_left[] = '

';

} else if(isset($node['isLastChild'])) {

$html_left[] = '

';

} else {

$html_left[] = '

';

}

$html_left[] = ($flag === true) ? "

{$node['title']}

  • " : "

{$node['title']}

";

$added_left[$id] = true;

}

if ($id != $fid && $node && !isset($added_right[$id])) {

$html_right[] = ($flag === true) ? '

' : '';

$added_right[$id] = true;

}

if ($flag == false) {

if($node) {

$cids = $child[$node['fid']];

for ($i = count($cids) - 1; $i >= 0; $i--) {

if ($cids[$i] == $id) {

array_splice($child[$node['fid']], $i, 1);

break;

}

}

if(count($child[$node['fid']]) == 0) {

$child[$node['fid']] = null;

}

}

array_push($html_left, array_pop($html_right));

array_shift($stack);

}

$loop++;

if($loop > 5000) return $html_left;

}

unset($child);

unset($obj);

return implode('', $html_left);

}

function get_tree_option($data, $fid) {

$stack = array($fid);

$child = array();

$added = array();

$options = array();

$obj = array();

$loop = 0;

$depth = -1;

foreach($data as $node) {

$pid = $node['fid'];

if(!isset($child[$pid])) {

$child[$pid] = array();

}

array_push($child[$pid], $node['id']);

$obj[$node['id']] = $node;

}

while (count($stack) > 0) {

$id = $stack[0];

$flag = false;

$node = isset($obj[$id]) ? $obj[$id] : null;

if (isset($child[$id])) {

for($i = count($child[$id]) - 1; $i >= 0; $i--) {

array_unshift($stack, $child[$id][$i]);

}

$flag = true;

}

if ($id != $fid && $node && !isset($added[$id])) {

$node['depth'] = $depth;

$options[] = $node;

$added[$id] = true;

}

if($flag == true){

$depth++;

} else {

if($node) {

for ($i = count($child[$node['fid']]) - 1; $i >= 0; $i--) {

if ($child[$node['fid']][$i] == $id) {

array_splice($child[$node['fid']], $i, 1);

break;

}

}

if(count($child[$node['fid']]) == 0) {

$child[$node['fid']] = null;

$depth--;

}

}

array_shift($stack);

}

$loop++;

if($loop > 5000) return $options;

}

unset($child);

unset($obj);

return $options;

}

?>

第二种:

这是使用TP来制作的无限级分类。

算法复杂度为T(n)=O(2n),只遍历两次数组.

关键代码其实只有一行$return[$v['pid']]['child'][$v['id']] = &$return[$k];

但是为了实现较为复杂的扩展,这里添加一些额外的信息//索引要和ID一致,这不是废话么

//pid是父元素

//不要出现死循环嵌套,就是AB互为父子

//不要出现相同name

$list[0]=['id'=>0,'pid'=>-1,'name'=>'A@0'];//-1用于后面的根目录判断

$list[1]=['id'=>1,'pid'=>0,'name'=>'A@1'];

$list[2]=['id'=>2,'pid'=>0,'name'=>'A@2'];

$list[3]=['id'=>3,'pid'=>2,'name'=>'A@3'];

$list[4]=['id'=>4,'pid'=>3,'name'=>'A@4'];

$list[5]=['id'=>5,'pid'=>0,'name'=>'A@5'];

$list[6]=['id'=>6,'pid'=>1,'name'=>'A@6'];

//先初始化目录

$return=[];

foreach($list as $v)

$return[$v['name']]=[];

//将每个目录与父目录进行拼接,并找到根目录

foreach($list as $k=>$v)

{

if($v['pid']>=0)

$return[$list[$v['pid']]['name']][$v['name']]=&$return[$v['name']];

else

$parent=$v['name'];

}

//打印根目录

print_r($return[$parent]);

输出1Array(

[A@1] => Array

(

[A@6] => Array

(

)

)

[A@2] => Array

(

[A@3] => Array

(

[A@4] => Array

(

)

)

)

[A@5] => Array

(

)

)

代码2/**

* Created by PhpStorm.

* User: Nikaidou-Shinku

* Date: 16/9/14

* Time: 17:12

*/

$list[] = ['id' => 0, 'pid' => -1, 'name' => 'A@0'];//-1用于后面的根目录判断

$list[] = ['id' => 1, 'pid' => 0, 'name' => 'A@1'];

$list[] = ['id' => 2, 'pid' => 0, 'name' => 'A@2'];

$list[] = ['id' => 3, 'pid' => 2, 'name' => 'A@3'];

$list[] = ['id' => 4, 'pid' => 3, 'name' => 'A@4'];

$list[] = ['id' => 5, 'pid' => 0, 'name' => 'A@5'];

$list[] = ['id' => 6, 'pid' => 1, 'name' => 'A@6'];

//先初始化目录

$return = [];

$parent = '';

foreach ($list as $v)

$return[$v['id']] = [

'id' => $v['id'],

'name' => $v['name'],

'pid' => $v['pid'],

'child' => '',

];

//将每个目录与父目录进行拼接,并找到根目录

foreach ($return as $k => $v) {

if ($v['pid'] >= 0)

$return[$v['pid']]['child'][$v['id']] = &$return[$k];

else

$parent = &$return[$k];

}

//打印根目录

var_export($parent);

输出2$aa=[

'id' => 0,

'name' => 'A@0',

'pid' => -1,

'child' =>

[

1 =>

[

'id' => 1,

'name' => 'A@1',

'pid' => 0,

'child' =>

[

6 =>

[

'id' => 6,

'name' => 'A@6',

'pid' => 1,

'child' => '',

],

],

],

2 =>

[

'id' => 2,

'name' => 'A@2',

'pid' => 0,

'child' =>

[

3 =>

[

'id' => 3,

'name' => 'A@3',

'pid' => 2,

'child' =>

[

4 =>

[

'id' => 4,

'name' => 'A@4',

'pid' => 3,

'child' => '',

],

],

],

],

],

5 =>

[

'id' => 5,

'name' => 'A@5',

'pid' => 0,

'child' => '',

],

],

]

第三种:

接下来这个无限级分类更为的简单。可以简化成使用5行代码就可以完成。function generateTree($items){

$tree = array();

foreach($items as $item){

if(isset($items[$item['pid']])){

$items[$item['pid']]['son'][] = &$items[$item['id']];

}else{

$tree[] = &$items[$item['id']];

}

}

return $tree;

}

$items = array(

1 => array('id' => 1, 'pid' => 0, 'name' => '安徽省'),

2 => array('id' => 2, 'pid' => 0, 'name' => '浙江省'),

3 => array('id' => 3, 'pid' => 1, 'name' => '合肥市'),

4 => array('id' => 4, 'pid' => 3, 'name' => '长丰县'),

5 => array('id' => 5, 'pid' => 1, 'name' => '安庆市'),

);

print_r(generateTree($items));

可以看到下面打印的结果:Array

(

[0] => Array

(

[id] => 1

[pid] => 0

[name] => 安徽省

[son] => Array

(

[0] => Array

(

[id] => 3

[pid] => 1

[name] => 合肥市

[son] => Array

(

[0] => Array

(

[id] => 4

[pid] => 3

[name] => 长丰县

)

)

)

[1] => Array

(

[id] => 5

[pid] => 1

[name] => 安庆市

)

)

)

[1] => Array

(

[id] => 2

[pid] => 0

[name] => 浙江省

)

)

上面生成树方法还可以精简到5行:function generateTree($items){

foreach($items as $item)

$items[$item['pid']]['son'][$item['id']] = &$items[$item['id']];

return isset($items[0]['son']) ? $items[0]['son'] : array();

}

但是上面的代码有个问题就是对数据库结构有点要求,每个节点要指明其父节点是谁,虽然实用性不高,但是还是能给大家带来启发,学习下不同类型的无限级分类。

本文原创发布php中文网,转载请注明出处,感谢您的尊重!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现无限分类的方法有多种,其中包括递归和非递归两种方式。下面分别介绍一下这两种方法的实现。 1. 递归实现无限分类 递归实现无限分类的方法是将分类数据作为一个树形结构来处理。具体实现步骤如下: (1)从数据库中获取所有分类数据,并按照父子关系组织为树形结构。 (2)遍历树形结构,输出每个分类的名称以及子分类的名称。 (3)对于每个子分类,重复步骤(2)。 下面是一个递归实现无限分类的示例代码: ```php function getCategoryTree($parent_id = 0, $level = 0) { $categories = getCategoryByParentId($parent_id); if (count($categories) > 0) { foreach ($categories as $category) { echo str_repeat('-', $level) . $category['name'] . '<br>'; getCategoryTree($category['id'], $level + 1); } } } function getCategoryByParentId($parent_id) { // 从数据库中获取 $parent_id 的所有子分类数据 // ... return $categories; } // 输出所有分类 getCategoryTree(); ``` 2. 非递归实现无限分类递归实现无限分类的方法是使用堆栈(或队列)来处理分类数据。具体实现步骤如下: (1)从数据库中获取所有分类数据,并按照父子关系组织为一个数组。 (2)将根分类(即 parent_id 为 0 的分类)入栈。 (3)从堆栈中取出一个分类,并输出该分类的名称。 (4)将该分类的所有子分类依次入栈。 (5)重复步骤(3)和(4),直到堆栈为空。 下面是一个非递归实现无限分类的示例代码: ```php function getCategoryTree() { $categories = getCategoryByParentId(0); $stack = array(); foreach ($categories as $category) { array_push($stack, array('category' => $category, 'level' => 0)); } while (count($stack) > 0) { $current = array_pop($stack); echo str_repeat('-', $current['level']) . $current['category']['name'] . '<br>'; $children = getCategoryByParentId($current['category']['id']); foreach ($children as $child) { array_push($stack, array('category' => $child, 'level' => $current['level'] + 1)); } } } function getCategoryByParentId($parent_id) { // 从数据库中获取 $parent_id 的所有子分类数据 // ... return $categories; } // 输出所有分类 getCategoryTree(); ``` 以上就是php实现无限分类的两种方法。从实现难度和效率上来看,递归方法更简单,但对于数据量较大的情况,可能会导致栈溢出。非递归方法虽然复杂一些,但可以处理更大的数据量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值