PHP实现无限极分类的两种方式示例【递归和引用方式】
时间:2022-07-27
本文章向大家介绍PHP实现无限极分类的两种方式示例【递归和引用方式】,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
本文实例讲述了PHP实现无限极分类的两种方式。分享给大家供大家参考,具体如下: 面试的时候被问到无限极分类的设计和实现,比较常见的做法是在建表的时候,增加一个PID字段用来区别自己所属的分类
$array = array(
array('id' = 1, 'pid' = 0, 'name' = '河北省'),
array('id' = 2, 'pid' = 0, 'name' = '北京市'),
array('id' = 3, 'pid' = 1, 'name' = '邯郸市'),
array('id' = 4, 'pid' = 2, 'name' = '朝阳区'),
array('id' = 5, 'pid' = 2, 'name' = '通州区'),
array('id' = 6, 'pid' = 4, 'name' = '望京'),
array('id' = 7, 'pid' = 4, 'name' = '酒仙桥'),
array('id' = 8, 'pid' = 3, 'name' = '永年区'),
array('id' = 9, 'pid' = 1, 'name' = '武安市'),
);
数据在数据库中存储大概是这个样子,怎么实现无限极递归呢,有两种常用的做法,递归和引用算法
递归算法
/**
* 递归实现无限极分类
* @param $array 分类数据
* @param $pid 父ID
* @param $level 分类级别
* @return $list 分好类的数组 直接遍历即可 $level可以用来遍历缩进
*/
function getTree($array, $pid =0, $level = 0){
//声明静态数组,避免递归调用时,多次声明导致数组覆盖
static $list = [];
foreach ($array as $key = $value){
//第一次遍历,找到父节点为根节点的节点 也就是pid=0的节点
if ($value['pid'] == $pid){
//父节点为根节点的节点,级别为0,也就是第一级
$value['level'] = $level;
//把数组放到list中
$list[] = $value;
//把这个节点从数组中移除,减少后续递归消耗
unset($array[$key]);
//开始递归,查找父ID为该节点ID的节点,级别则为原级别+1
getTree($array, $value['id'], $level+1);
}
}
return $list;
}
/*
* 获得递归完的数据,遍历生成分类
*/
$array = getTree($array);
foreach($array) as $value{
echo str_repeat('--', $value['level']), $value['name'].'<br / ';
}
输出结果 无限极分类实现ok
河北省 –邯郸市 —-永年区 –武安市 北京市 –朝阳区 —-望京 —-酒仙桥 –通州区
引用算法
function generateTree($array){
//第一步 构造数据
$items = array();
foreach($array as $value){
$items[$value['id']] = $value;
}
//第二部 遍历数据 生成树状结构
$tree = array();
foreach($items as $key = $value){
if(isset($items[$item['pid']])){
$items[$item['pid']]['son'][] = &$items[$key];
}else{
$tree[] = &$items[$key];
}
}
return $tree;
}
//经过第一步 数据变成了这样
Array
(
[1] = Array
(
[id] = 1
[pid] = 0
[name] = 河北省
[children] = Array
(
)
)
[2] = Array
(
[id] = 2
[pid] = 0
[name] = 北京市
[children] = Array
(
)
)
[3] = Array
(
[id] = 3
[pid] = 1
[name] = 邯郸市
[children] = Array
(
)
)
[4] = Array
(
[id] = 4
[pid] = 2
[name] = 朝阳区
[children] = Array
(
)
)
[5] = Array
(
[id] = 5
[pid] = 2
[name] = 通州区
[children] = Array
(
)
)
[6] = Array
(
[id] = 6
[pid] = 4
[name] = 望京
[children] = Array
(
)
)
[7] = Array
(
[id] = 7
[pid] = 4
[name] = 酒仙桥
[children] = Array
(
)
)
[8] = Array
(
[id] = 8
[pid] = 3
[name] = 永年区
[children] = Array
(
)
)
[9] = Array
(
[id] = 9
[pid] = 1
[name] = 武安市
[children] = Array
(
)
)
)
//第一步很容易就能看懂,就是构造数据,现在咱们仔细说一下第二步
$tree = array();
//遍历构造的数据
foreach($items as $key = $value){
//如果pid这个节点存在
if(isset($items[$value['pid']])){
//把当前的$value放到pid节点的son中 注意 这里传递的是引用 为什么呢?
$items[$value['pid']]['son'][] = &$items[$key];
}else{
$tree[] = &$items[$key];
}
}
//这个方法的核心在于引用,php变量默认的传值方式是按指传递
//也就是说 假如说 遍历顺序是 河北省 邯郸市 当遍历到河北省时 会把河北省放到tree中 遍历到邯郸市时 会把邯郸市放到河北省的子节点数组中 但是!!! 这会儿的tree数组中 河北省已经放进去了 根据php变量按值传递的规则 你并没有更改tree数组中的河北省的数据 所以这里用到了引用传递
//当你对河北省做更改时,tree数组中的河北省也一并做了更改 下面我们做个实验 我们把引用传递去掉,看一下结果
//使用普通传值输出结果
Array
(
[0] = Array
(
[id] = 1
[pid] = 0
[name] = 河北省
)
[1] = Array
(
[id] = 2
[pid] = 0
[name] = 北京市
)
)
//可以看到 只有河北省和北京市输出出来了 因为他们俩是第一级节点 而且排行1和2,放到$tree数组中之后,没有使用引用传递,那么后续对他俩的子节点的操作都没有在$tree中生效,现在我们更改一下顺序 把邯郸市放到河北省的前面 那么根据咱们的推断 那么邯郸市就应该出现在tree数组里
//邯郸市放到河北省前面的输出结果
Array
(
[0] = Array
(
[id] = 1
[pid] = 0
[name] = 河北省
[son] = Array
(
[0] = Array
(
[id] = 3
[pid] = 1
[name] = 邯郸市
)
)
)
[1] = Array
(
[id] = 2
[pid] = 0
[name] = 北京市
)
)
//果然是这样 那么证明我们的推断是正确的 现在我们把引用传值改回去 再看一下
//使用引用传值输出结果
Array
(
[1] = Array
(
[id] = 1
[pid] = 0
[name] = 河北省
[children] = Array
(
[0] = Array
(
[id] = 3
[pid] = 1
[name] = 邯郸市
[children] = Array
(
[0] = Array
(
[id] = 8
[pid] = 3
[name] = 永年区
)
)
)
[1] = Array
(
[id] = 9
[pid] = 1
[name] = 武安市
)
)
)
[2] = Array
(
[id] = 2
[pid] = 0
[name] = 北京市
[children] = Array
(
[0] = Array
(
[id] = 4
[pid] = 2
[name] = 朝阳区
[children] = Array
(
[0] = Array
(
[id] = 6
[pid] = 4
[name] = 望京
)
[1] = Array
(
[id] = 7
[pid] = 4
[name] = 酒仙桥
)
)
)
[1] = Array
(
[id] = 5
[pid] = 2
[name] = 通州区
)
)
)
)
//树状结构完美的输出出来了 这个方法的核心就是引用传值
更多关于PHP相关内容感兴趣的读者可查看本站专题:《PHP数据结构与算法教程》、《php程序设计算法总结》、《php字符串(string)用法总结》、《PHP数组(Array)操作技巧大全》、《PHP常用遍历算法与技巧总结》及《PHP数学运算技巧总结》
希望本文所述对大家PHP程序设计有所帮助。
- 技术分享 | 浅谈 RAS
- Sniper-OJ 练习平台多题WriteUp
- 怎么能学透一个知识点
- Jarvis-OJ平台多题WriteUp分享
- 会员提问 之 JS中的私有方法有什么意义?
- 本周末的QQ群视频--还是电商网站的事
- 【译】使用Apache的mod重写来保护你的C2 Empire
- 大白话,设计一个购物车对象
- 【译】Cromos – 下载并注入代码到谷歌 Chrome 浏览器扩展中
- X-NUCA 2017第三期 WriteUp
- 学习分享 | Flipped Ciphertext Bits
- 聊一下JavaScript定时器
- java redis 通用组建
- 学习分享 | Padding Oracle
- php概述
- php教程
- php环境搭建
- PHP书写格式
- php变量
- php常量
- PHP注释
- php数组
- php字符串 string
- PHP整型 integer
- PHP浮点型 float
- php布尔型
- php数据类型之数组
- php数据类型之对象
- php数据类型之null
- php数据类型之间的转换
- php运算符
- php表达式
- PHP循环控制
- PHP流程控制
- php函数
- php全局变量
- PHP魔术变量
- php命名空间
- php 日期
- PHP包含文件
- php文件
- PHP 文件上传
- php Cookies
- php Sessions
- php email
- php安全email
- php错误处理
- PHP异常处理
- php过滤器
- PHP 高级过滤器
- php json
- php 表单
- PHP MySQL 简介
- PHP 连接 MySQL
- php创建数据库
- php 创建表
- php mysq 插入数据
- PHP MySQL 插入多条数据
- PHP MySQL 预处理语句
- php mysql 读取数据
- php mysql where
- PHP MySQL Order By
- PHP MySQL Update
- PHP MySQL Delete
- php ODBC
- 虚拟机kali安装vmtools
- Android动画学习笔记之补间动画
- [- Flutter 数据&状态篇 -] setState
- flutter 自定义websocket路由的实现
- Flutter开发之路由与导航的实现
- Android BSearchEdit 搜索结果选择框的实例代码
- 使用AccessibilityService实现微信自动切换账号功能
- Android评分RationBar控件使用详解
- Flutter里面错误捕获的正确方法
- django3 websockets
- 使用AccessibilityService实现自动遍历点赞功能
- Android自定义字母导航栏
- [-Flutter 自组篇-] 圆形进度条
- Flutter 滚动监听及实战appBar滚动渐变的实现
- Android 开机充电图标和充电动画效果