资讯专栏INFORMATION COLUMN

递归算法造成的问题分析与解决

gekylin / 1620人阅读

摘要:整理一下,形成今天的内容算法中的递归算法。解决来看一下,最终形态的递归方法是什么样子递归运算创建树结构声明静态变量给静态变量累加值赋值闭合标签这样就可以解决了。所以,在之后的递归算法中,应该小心谨慎,避免出现问题。

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

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

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

什么是递归

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

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

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

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

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

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

问题所在

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

数组结构

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

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

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

问题代码
function creatHtmlTree($tree)
{
    // 生命一个静态变量
    static $htmlTree;
    $htmlTree .= "
    "; foreach ($tree as $key => $value) { $htmlTree .= "
  • {$value["name"]} Goes somewhere"; if (isset($value["childs"]) && is_array($value["childs"])) { // 每次的结果累加到静态变量上 $html = creatHtmlTree($value["childs"]); $htmlTree .= $html; } $htmlTree .= "
  • "; } $htmlTree .= "
"; return $htmlTree; }

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

问题分析

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

static $htmlTree;
$htmlTree .= "
    ";

以及if里的

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

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

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

改为:

creatHtmlTree($value["childs"]);

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

$htmlTree .= "
    "; $htmlTree .= "
  • {$value["name"]} Goes somewhere"; $htmlTree .= "
  • "; $htmlTree .= "
";

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

解决

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

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

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

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

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

测试

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

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 "
";
    echo "========================开始========================";
    echo "
"; if( $arr ){ print_r($arr); } else { echo "此值为空"; } echo "
"; echo "========================结束========================"; echo "
"; } /** * 多维数组树形结构 */ 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 .= "
    "; foreach ($tree as $key => $value) { // 给$htmlTree变量累加值 $htmlTree .= "
  • {$value["name"]} Goes somewhere"; if (isset($value["childs"]) && is_array($value["childs"])) { // 递归中每次的结果累加到$htmlTree $htmlTree .= creatHtmlTree($value["childs"]); } $htmlTree .= "
  • "; } // 赋值ul闭合标签 $htmlTree .= "
"; return $htmlTree; } $tree = tree($data); $htmlTree = creatHtmlTree($tree); p($tree); p($htmlTree);
总结

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

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

补充

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

递归需要有边界条件、递归前进段和递归返回段

当边界条件不满足时,递归前进;当边界条件满足时,递归返回

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/26306.html

相关文章

  • 数据结构和算法类面试题javascript代码实现

    摘要:正文面试题重建二叉树题目输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。前序遍历序列为,中序遍历序列,。确定了左右子树后递归处理。方法方法面试题在时间删除链表结点。 写在前面 本文的题目均来自于剑指offer中的题目,题目序号保持了书中的题目序号,由于某些题目并不适合于javascript这种语言,所以这些题目就没有写在本篇博客中,因此会出现题目序号的中断。 正文 面试题6:...

    Dean 评论0 收藏0
  • 数据结构算法之精讲「递归系列」

    摘要:终止条件递推公式递归的分类通过做大量的题,根据递归解决不同的问题,引申出来的几种解决和思考的方式。我们通过层与层之间的计算关系用递推公式表达出来做计算,经过层层的递归,最终得到结果值。 showImg(https://segmentfault.com/img/remote/1460000019222330); 前言 几个月之前就想写这样一篇文章分享给大家,由于自己有心而力不足,没有把真...

    zhichangterry 评论0 收藏0
  • 算法系列——JavaScript中广度优先搜索思想实现

    摘要:散列表上面的地图向我们展示了如何用广度优先搜索的思想找到北京到广州的最短路线。在广度优先搜索中,我们需要用到队列的这种思想来实现查找。建立了下面这个模型武汉广州西藏上海上海武汉广州代码完整实现,利用递归和广度优先搜索的思想实现。 什么是广度优先搜索? 如果只是是背概念,幼儿园的小朋友都能背下来念给你听。 假设看这篇文章的都和我一样是个前端工程师,我们要从广度优先搜索(BFS)中学到什么...

    everfly 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<