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

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

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

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

什么是递归

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

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

递归的能力

一样引用百科的一句话,我的以为很是经典:编程

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

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

本身以前对递归的理解就是本身调用本身,经过屡次的本身调用自身,经过同一套程序方法,来达到解决问题的目的;这种方法能够明显的减小代码量,并且灵活,尤为是在多重循环的时候,能够采用递归来替代。可是这种方法也有缺点,就是增长了程序了运行速度,并且有时候可能会由于编码不当,形成死循环、栈溢出等问题。可是只要用好,解决问题仍是不差的;数组

问题所在

今天在工做中,遇到一个把无限分类的多维数组转换成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. 当边界条件不知足时,递归前进;当边界条件知足时,递归返回

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

相关文章
相关标签/搜索