PHP面试题精讲—无限级分类/无限分类的递归算法和非递归算法-带源码建议收藏

Posted 雨果虾滑猫

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PHP面试题精讲—无限级分类/无限分类的递归算法和非递归算法-带源码建议收藏相关的知识,希望对你有一定的参考价值。

日拱一卒无有尽,功不唐捐终入海 💋

经典问题-无限级分类

无限级分类,也被称为无限分类,如下图所示,他是一个非常经典的问题。

在这里插入图片描述
最经典的应用场景就是后台系统的菜单,包括但是不仅限于

  • 省市区直辖市下拉菜单
  • 信息系统后台管理的菜单管理
  • 实际工作业务中的组织层级管理

那么无限级分类为什么经典呢?原因有三:

  1. 了解面试者是否会用递归算法
  2. 观察面试者处理实际问题的解决思路
  3. 根据实际代码看面试者对语言(php)的熟练程度

接下来,让我带你一层一层的分析问题,从中通过深度思考,学到更多的东西,这样不仅对于面试,并且对于以后的工作学习也是有帮助的。

问题描述

给出如下数组结构,输出返回层级菜单。

输入

$arr = [
            ['id'=>1,'pid'=>0,'name'=>'内容管理'],
            ['id'=>2,'pid'=>1,'name'=>'内容管理1'],
            ['id'=>3,'pid'=>1,'name'=>'内容管理2'],
            ['id'=>4,'pid'=>3,'name'=>'内容管理22'],
            ['id'=>5,'pid'=>0,'name'=>'附件管理'],
            ['id'=>6,'pid'=>5,'name'=>'内容管理'],
            ['id'=>7,'pid'=>6,'name'=>'内容管理1'],
            ['id'=>8,'pid'=>7,'name'=>'模块1'],
            ['id'=>9,'pid'=>8,'name'=>'模块11'],
            ['id'=>10,'pid'=>9,'name'=>'模块111'],
        ];

输出结果为按层级的数组

问题分析-为什么他是一个高频问题?

原因是通过这个问题的考察,他能够看到你解决问题的思路。

可以通过递归解决,通过递归的写法,面试官就能看出来你对递归条件的判断,什么时候跳出递归的界限是否清晰,函数调用是否合理。

解决问题

1.递归方法

递归,就是在运行的过程中调用自己。

递归可以说是分而治之的思想的体现,将一个问题分解成一个小问题,并且在判断范围内调用自己来解决一个问题,直到这个问题不再适用于自己的解决范围。

用最快的方式理解递归,只需要记住这几点

  1. 递归的界限在哪里结束
  2. 递归的调用在哪里执行
  3. 维护的结果是如何传递的
    public function makeTree($array, $pid =0, $level = 0) //传递结果
    {
        static $list = [];
        foreach ($array as $key => $value) {
            if ($value['pid'] == $pid) { //递归的界限
                $value['level'] = $level;
                $value['name'] = str_repeat('-',$level).$value['name'];
                $list[] = $value;
                unset($array[$key]);
                $this->makeTree($array, $value['id'], $level + 1); //递归的调用 
            }
        }
        return $list;
    }

输出结果是一个按层级排列的一维数组,name已经按层级增加了前缀,这样的数组可以直接给下拉菜单使用。

array (
  0 => 
  array (
    'id' => 1,
    'pid' => 0,
    'name' => '内容管理',
    'level' => 0,
  ),
  1 => 
  array (
    'id' => 2,
    'pid' => 1,
    'name' => '-内容管理1',
    'level' => 1,
  ),
  2 => 
  array (
    'id' => 3,
    'pid' => 2,
    'name' => '--内容管理2',
    'level' => 2,
  ),
  3 => 
  array (
    'id' => 7,
    'pid' => 3,
    'name' => '---内容管理22',
    'level' => 3,
  ),
  4 => 
  array (
    'id' => 4,
    'pid' => 7,
    'name' => '----模块1',
    'level' => 4,
  ),
  5 => 
  array (
    'id' => 8,
    'pid' => 0,
    'name' => '附件管理',
    'level' => 0,
  ),
  6 => 
  array (
    'id' => 5,
    'pid' => 8,
    'name' => '-模块11',
    'level' => 1,
  ),
  7 => 
  array (
    'id' => 9,
    'pid' => 5,
    'name' => '--内容管理',
    'level' => 2,
  ),
  8 => 
  array (
    'id' => 6,
    'pid' => 9,
    'name' => '---模块111',
    'level' => 3,
  ),
  9 => 
  array (
    'id' => 10,
    'pid' => 6,
    'name' => '----内容管理1',
    'level' => 4,
  ),
)

那么这个非常经典的递归方法,我们如何分析其中的问题呢?

这个调用的结束点在,找不到下一级为止,即当前元素的pid和下一次循环的pid都不一致

通过增加变量times可以发现,10个元素下函数调用次数为11次。

通过前后执行函数memory_get_usage(),得出内存使用: 5.367188 kb

2.非递归方法

递归方法的缺点在于比较消耗资源,那么不用递归也是能解决这个问题的。

先给出源码

    function makeTree($arr)
    {
        $pid = $arr[0]['pid'];
        $arr_assert = [];
        $arr_new = [];
        foreach ($arr as $value) {
            $arr_new[$value['id']] = $value;
            if (!isset($arr_assert[$value['pid']])) {
                $arr_assert[$value['pid']]['start'] = 0;
                $arr_assert[$value['pid']]['end'] = 0;
            }
            $arr_assert[$value['pid']][] = $value['id'];
            ++$arr_assert[$value['pid']]['end'];
        }
        $result = [];
        $count = count($arr_new);
        $offset = 0;
        while ($offset < $count) {
            if (isset($arr_assert[$pid]) && $arr_assert[$pid]['start'] < $arr_assert[$pid]['end']) {
                $id = $arr_assert[$pid]['start'];
                ++$arr_assert[$pid]['start'];
                $pid = $arr_assert[$pid][$id];
                $result[] = $arr_new[$pid];
                ++$offset;
            } else
                $pid = $arr_new[$pid]['pid'];
        }
        return $result;
    }

这一步得出的结构是树形的结构

array (
  0 => 
  array (
    'id' => 1,
    'pid' => 0,
    'name' => '内容管理',
  ),
  1 => 
  array (
    'id' => 2,
    'pid' => 1,
    'name' => '内容管理1',
  ),
  2 => 
  array (
    'id' => 3,
    'pid' => 2,
    'name' => '内容管理2',
  ),
  3 => 
  array (
    'id' => 7,
    'pid' => 3,
    'name' => '内容管理22',
  ),
  4 => 
  array (
    'id' => 4,
    'pid' => 7,
    'name' => '模块1',
  ),
  5 => 
  array (
    'id' => 8,
    'pid' => 0,
    'name' => '附件管理',
  ),
  6 => 
  array (
    'id' => 5,
    'pid' => 8,
    'name' => '模块11',
  ),
  7 => 
  array (
    'id' => 9,
    'pid' => 5,
    'name' => '内容管理',
  ),
  8 => 
  array (
    'id' => 6,
    'pid' => 9,
    'name' => '模块111',
  ),
  9 => 
  array (
    'id' => 10,
    'pid' => 6,
    'name' => '内容管理1',
  ),
)

总结

对于无限级分类这个问题,由于在实际项目应用非常广泛,所以这是一个概率非常大会出现的面试题。

以上是关于PHP面试题精讲—无限级分类/无限分类的递归算法和非递归算法-带源码建议收藏的主要内容,如果未能解决你的问题,请参考以下文章

php实现无限级分类(递归方法)

PHP迭代与递归实现无限级分类

PHP利用递归函数实现无限级分类的方法_php技巧 - PHP

PHP.32-TP框架商城应用实例-后台10-商品分类-需求分析创建无限级商品分类,递归

PHP实现无限极分类的两种方式,递归和引用

php无限级分类