原文是在我自己博客中,小伙伴也可以点阅读原文进行跳转查看,还有好听的背景音乐噢~

递归,在编码中应该算是一种很常见的算法了。之前在学习C语言的时候,也同样了解过一些基本的算法,比如斐波那契。在学习的时候,对算法这种编程技巧就有了一种浓浓的敬畏之心,因为觉得会算法的人就很厉害了,可以把很长的代码块通过一段简短的算法解决并得到想要的结果。

今天在实际工作中也遇到了算法中一些问题。整理一下,形成今天的内容【算法中的递归算法】。

什么是递归

借用百科的一段话来表述就是:

一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法。

递归的能力

同样引用百科的一句话,个人觉得非常经典:

用有限的语句来定义对象的无限集合;

这句话什么意思呢,通俗点来理解就是,我程序只有一套,但是我可以通过递归(自身调用自身)的特性,不管你有多少个值,我都能妥妥的给你按照特定的程序逻辑处理喽。(就是这么强势,嘿嘿!)

自己之前对递归的理解就是自己调用自己,通过多次的自己调用自身,通过同一套程序方法,来达到解决问题的目的;这种方法可以明显的减少代码量,而且灵活,尤其是在多重循环的时候,可以采用递归来替代。但是这种方法也有缺点,就是增加了程序了运行速度,而且有时候可能会因为编码不当,造成死循环、栈溢出等问题。但是只要用好,解决问题还是不差的;

问题所在

今天在工作中,遇到一个把无限分类的多维数组转换成html树的时候,就遇到了点小麻烦,可能是因为一时马虎,当局者迷的缘故,自己就像掉进死循环里,一直出不来,后来,也是在请教身边的朋友后,才得到解决,下面我们来看一下出现了什么问题(其实问题已经提在了SF社区上,问题标题是多维数组分类树 组合html树的问题?(递归),有兴趣的小伙伴可以去看下):

数组结构

最初的数组结构是一个无限分类的多维数组:

由上图可以看到,这个数组的childs下标里面对应的就是子分类,分类可以有无限个。我们要把它组装成下图的理想形态:

虽然看着很简单,但是实际上走了不少弯路,最后卡在了一个点上,始终没出来。我最开始的递归方法是:

问题代码

function creatHtmlTree($tree)
{// 生命一个静态变量static $htmlTree;$htmlTree .= '<ul>';foreach ($tree as $key => $value) {$htmlTree .= "<li><span><i class='icon-folder-open'></i>{$value['name']} </span> <a href=''>Goes somewhere</a>";if (isset($value['childs']) && is_array($value['childs'])) {// 每次的结果累加到静态变量上$html = creatHtmlTree($value['childs']);$htmlTree .= $html;} $htmlTree .= "</li>";}$htmlTree .= "</ul>";return $htmlTree;
}

通过测试得到了下图的错误内容:

问题分析

我们可以看到,它给$htmlTree这个变量给了多余的值,通过求教才明白,我的代码中

static $htmlTree;
$htmlTree .= '<ul>';

以及if里的

$html = creatHtmlTree($value['childs']);
$htmlTree .= $html;

代码逻辑写的有问题,问题在于,既然设定了$htmlTree为静态变量,那么在递归中的每一次计算中,都默认已经$htmlTree赋予了最后的计算结果,我在if里又把结果加了一次,所以才造成了输出出现问题的情况,那么如何改成呢?只需把:

$html = creatHtmlTree($value['childs']);
$htmlTree .= $html;

改为:

creatHtmlTree($value['childs']);

即可。这样,他在递归运算的时候就可以通过

$htmlTree .= '<ul>';$htmlTree .= "<li><span><i class='icon-folder-open'></i>{$value['name']} </span> <a href=''>Goes somewhere</a>";$htmlTree .= "</li>";$htmlTree .= "</ul>";

这四行代码来给$htmlTree累加数值就可以了。

解决

来看一下,最终形态的递归方法是什么样子:

// 递归运算创建html树结构
function creatHtmlTree($tree)
{// 声明静态变量static $htmlTree;$htmlTree .= '<ul>';foreach ($tree as $key => $value) {// 给静态$htmlTree变量累加值$htmlTree .= "<li><span><i class='icon-folder-open'></i>{$value['name']} </span> <a href=''>Goes somewhere</a>";if (isset($value['childs']) && is_array($value['childs'])) {creatHtmlTree($value['childs']);} $htmlTree .= "</li>";}// 赋值ul闭合标签$htmlTree .= "</ul>";return $htmlTree;
}

这样就可以解决了。同样还有另外一种方式,那就是通过返回值的方式,来进行递归运算:

// 递归运算创建html树结构
function creatHtmlTree($tree)
{// $htmlTree为普通局部变量;$htmlTree .= '<ul>';foreach ($tree as $key => $value) {// 给变量$htmlTree累加值$htmlTree .= "<li><span><i class='icon-folder-open'></i>{$value['name']} </span> <a href=''>Goes somewhere</a>";if (isset($value['childs']) && is_array($value['childs'])) {// 递归中每次的结果累加到$htmlTree$htmlTree .= creatHtmlTree($value['childs']);} $htmlTree .= "</li>";}// 赋值ul闭合标签$htmlTree .= "</ul>";return $htmlTree;
}

通过这种返回值累加的算法,也同样可以得到想要的结果。

测试

今天为了测试和解决递归算法带来的问题,特意找了段代码进行测试,也是我下午一直在实验的demo,手痒痒的小伙伴,可以立马copy到本地亲自体验一下:

<?php $data = [['id'=>1,'parentid'=>0,'name'=>'中国'],['id'=>2,'parentid'=>0,'name'=>'美国'],['id'=>3,'parentid'=>0,'name'=>'韩国'],['id'=>4,'parentid'=>1,'name'=>'北京'],['id'=>5,'parentid'=>1,'name'=>'上海'],['id'=>6,'parentid'=>1,'name'=>'广西'],['id'=>7,'parentid'=>6,'name'=>'桂林'],['id'=>8,'parentid'=>6,'name'=>'南宁'],['id'=>9,'parentid'=>6,'name'=>'柳州'],['id'=>10,'parentid'=>2,'name'=>'纽约'],['id'=>11,'parentid'=>2,'name'=>'华盛顿'],['id'=>12,'parentid'=>3,'name'=>'首尔'],
];/**格式化数组输出**/
function p($arr)
{echo "<pre>";echo '========================开始========================';echo "</br>";if( $arr ){print_r($arr);} else {echo '此值为空';}echo "</br>";echo '========================结束========================';echo "</pre>";
}/*** 多维数组树形结构*/
function tree($data, $pid = 0)
{$children = [];foreach ($data as $key => $value) {if ($value['parentid'] == $pid) {$children[] = $value;}}if (empty($children)) {return null;}foreach ($children as $key => $value) {$chid = tree($data, $value['id']);if ($chid != null) {$children[$key]['childs'] = $chid;}}return $children;
}// 递归运算创建html树结构
function creatHtmlTree($tree)
{// $htmlTree为普通局部变量;$htmlTree .= '<ul>';foreach ($tree as $key => $value) {// 给$htmlTree变量累加值$htmlTree .= "<li><span><i class='icon-folder-open'></i>{$value['name']} </span> <a href=''>Goes somewhere</a>";if (isset($value['childs']) && is_array($value['childs'])) {// 递归中每次的结果累加到$htmlTree$htmlTree .= creatHtmlTree($value['childs']);} $htmlTree .= "</li>";}// 赋值ul闭合标签$htmlTree .= "</ul>";return $htmlTree;
}$tree = tree($data);
$htmlTree = creatHtmlTree($tree);p($tree);
p($htmlTree);

总结

算法,这门技巧,是我向往的高级玩意儿。觉得它挺炫的,在开头我就有提到,可以用极短的代码解决复杂的业务程序,大大减少的代码量。但它同样也像一颗隐形炸弹一样,也充满着威胁。所以,在之后的递归算法中,应该小心谨慎,避免出现问题。

好了,今天就分享到这里,以上。

补充

在百科里看到递归解释的两句话,也同样经典,奉上:

  1. 递归需要有边界条件、递归前进段和递归返回段
  2. 当边界条件不满足时,递归前进;当边界条件满足时,递归返回

这大概说的就是递归的运行条件吧。
完。

递归算法造成的问题分析与解决相关推荐

  1. php session_start() 非常慢,PHP session_start()很慢问题分析与解决办法

    本文章来给各位同学介绍一下关于PHP session_start()很慢问题分析与解决办法,希望碰到此问题的同学可进入参考. 最近在做东西的时候发现一个问题 有一个接口挂了 ,然后进行测试访问地址的时 ...

  2. Spring - 同一个类中的方法互相调用,注解失效问题的分析和解决(转)

    Spring - 同一个类中的方法互相调用,注解失效问题的分析和解决(转) 参考文章: (1)Spring - 同一个类中的方法互相调用,注解失效问题的分析和解决(转) (2)https://www. ...

  3. mysql 资源占用过高分析和解决方法

    mysql 资源占用过高分析和解决方法 参考文章: (1)mysql 资源占用过高分析和解决方法 (2)https://www.cnblogs.com/luoa/p/10422210.html 备忘一 ...

  4. aliyun oss 文件上传 java.net.SocketTimeoutException Read timed out 问题分析及解决

    aliyun oss 文件上传 java.net.SocketTimeoutException Read timed out 问题分析及解决 参考文章: (1)aliyun oss 文件上传 java ...

  5. tomcat无法正常关闭问题分析及解决

    tomcat无法正常关闭问题分析及解决 参考文章: (1)tomcat无法正常关闭问题分析及解决 (2)https://www.cnblogs.com/nuccch/p/9052692.html 备忘 ...

  6. Android使用Handler造成内存泄露的分析及解决方法

    Android使用Handler造成内存泄露的分析及解决方法 参考文章: (1)Android使用Handler造成内存泄露的分析及解决方法 (2)https://www.cnblogs.com/xu ...

  7. java.lang.ArrayIndexOutOfBoundsException异常分析及解决

    2019独角兽企业重金招聘Python工程师标准>>> java.lang.ArrayIndexOutOfBoundsException异常分析及解决 这是一个非常常见的异常,从名字 ...

  8. mysql数据库连接过多的错误,可能的原因分析及解决办法

    mysql数据库连接过多的错误,可能的原因分析及解决办法 来源:网络采集 作者:未知 系统不能连接数据库,关键要看两个数据: 1.数据库系统允许的最大可连接数max_connections.这个参数是 ...

  9. vue在微信里面的兼容问题_微信H5页面兼容性问题分析及解决方法

    随着H5页面越来越流行,越来越多的开发者都开始用最近H5做微信公众号,在这个过程中自然也会遇到不少的问题.小编在这里整理了五种常见的微信H5页面兼容性问题,来和大家分析一下问题的详情.出现原因以及相对 ...

最新文章

  1. linux内核路由反向检查,Linux非对称路由
  2. 养娃时做过的蠢事,程序员必看!
  3. linux c send recv MSG_NOSIGNAL参数
  4. java中的mmap实现--转
  5. Redis持久化机制 -全量同步与增量同步的区别
  6. angular js一factory,service,provider创建服务
  7. html中文乱码_Nginx目录浏览的中文显示问题订正
  8. 微软最爽命令行工具发布!
  9. 在不如意的世界里全力以赴_我如何在“外展之旅”中全力以赴
  10. System.Threading.Timer 定时器的用法
  11. 向android模拟器中复制文件报out of memory错误解决
  12. 3V升压5V芯片,3V升压5V电路图
  13. CodeMeter***大赛战况:百人参赛,无人摘金!
  14. HC-05嵌入式蓝牙串口通讯
  15. Elasticsearch查询数据总条数1万条限制
  16. LintCode168.吹气球
  17. 山洋服务器R系列和Q系列区别,仔细分析:aoc u系列和q系列有区别吗?说说哪个好?大家看法如何...
  18. linux电子相册程序,基于Linux电子相册的
  19. AD7606系列ADC的相关内容
  20. 【win10自定义默认应用】

热门文章

  1. 0113——代理模式
  2. 第3章 一切基于pom
  3. 使用C#Visual Studio2015编写Android应用程序详细步骤
  4. .net连接ORACLE数据库
  5. RDLC报表开发分组笔记
  6. 即时通讯学习笔记003---Tigase代码框架解读
  7. SpringCloud学习笔记020---MongoDb之json与bson的区别
  8. 跑通通过人脸测试心率程序
  9. 2013浙大878计算机基础综合大题答案解析
  10. 随想录(canvas双缓存下的性能分析)