javascript中怎么读懂递归函数,读懂递归函数的代码逻辑?

一直不能读懂javascript中的递归函数,不清楚里面的层层调用是什么逻辑?每次碰到递归函数就会晕。
比如下面一个javascript组合排序的代码,里面就是递归实现:

var arr = ['A','B','C','D',"E","F","G"];

function show(arr,num){
    
    var resultNum = 0;
    var iNow = 1;
    
    if(num==1){
        return arr.length;
    }
    
    function change(arr,iNow){
        
        for(var i=0;i<arr.length;i++){
            
            var result = arr.concat();
            result.splice(i,1);

            if( iNow == num ){
                resultNum += result.length;
            }else{
                change(result,iNow+1);
            }
        }
    }
    change(arr,iNow+1);
    return resultNum;
}

console.log(show(arr,5));

看了很多遍,都不知道它里面的实现逻辑是什么?也不知道怎么打断点分析代码,就是感觉反复调用,让人很晕,怎么办?
求javascript大神就拿上面这个例子帮忙分析下,代码逻辑怎么实现的?如果能读懂递归函数,后面再慢慢尝试写递归函数。


Eidt
谁能解释解释这个递归?

function f(m,n)
{
    if(m==0)return n+1;
    if(n==0)return f(m-1,1);
    return f(m-1,f(m,n-1));
}
阅读 5.8k
6 个回答
var arr = ['A','B','C','D',"E","F","G"];

function show(arr,num){
    debugger
    var resultNum = 0;
    var iNow = 1;
    
    if(num==1){
        return arr.length;
    }
    
    function change(arr,iNow){
        
        for(var i=0;i<arr.length;i++){
            
            var result = arr.concat();
            result.splice(i,1);

            if( iNow == num ){
                resultNum += result.length;
            }else{
                change(result,iNow+1);
            }
        }
    }
    change(arr,iNow+1);
    return resultNum;
}

console.log(show(arr,5));

打开控制台 执行一下, 按F10 逐步执行.

某些人说调不出, 只能说头脑逻辑性不够. 不能怪方法不行.
首先接触到一个递归, 先看函数内部做了什么, 看不懂, 调试一遍,
看内部的不懂的函数或分支 做了什么.在不明白, 说明你的智商只如嘲讽一般.

其次这个函数目的就是算阶乘.
!arr.length/!(arr.length - 5) 叹号为阶乘

用“反复调用”来描述递归并不准确,个人认为更准确的描述应该是“递进调用”——区别在于一个强调的是次数的增加,另一个强调的是层次的递进。

抛开调用栈的一套理论,想要快速读懂一段递归函数,最关键的是准确描述这个函数到底做了什么,具体来讲一个比较可行的方法是搞清楚这个函数的参数和返回 —— 这两点搞懂之后就可以吧函数中所有出现递归的地方替换掉,这样就得到一个普通的函数,分析起来也就简单很多。

另外强烈推荐配合算法流程图来理解递归,效果会更好。

要看懂递归你要知道他是如何迭代的,比如n!,把4!记作fun(4),则5!就是5*fun(4)这个很容易理解,所以n!可以这样表示:

function fun(n){
    return n > 1 ? n*fun(n-1) : n < 1 ? 0 : 1;
}

另外一个递归算法的启蒙问题就是汉诺塔问题,题主可以认真看一下这个思想,实际上跟n!是一样的。回到你的问题,当iNownum相等的时候change(arr,iNow)实际上是不是arr.length* (arr.length - 1) ?我们把他简写一下iNow == numchange(n,iNow) = n * (n - 1)。再看一下change整个函数,当iNow != num的时候change(n, iNow)实际上是调用了change(n - 1,iNow + 1)并且循环了n次,是不是可以记成change(n, iNow) = n * change(n - 1, iNow + 1)?所以把具体的问题展开就是这样的:

clipboard.png

其实学习代码最好就是在脑里运算一遍。递归其实,很简单,不满足条件就调用自己,可以拿纸自己模拟计算,一次就弄明白了。比如。
`function a(b){
if (b<2)return false;
b--;
a(b);
}`

昨天手机没有写完。如上面的代码 我们执行
a(3);那么3相当于函数内的b,判断b大于2,那么执行b减一,即b等于2,然后执行a(2),2相当于函数内的b,判断b,b等于2,则执行b减一,即b等于1,执行a(1),1相当于函数内的b,判断b小于2,那么返回false,最终a(3)返回false。

可以这样在脑子里计算一遍,这样才能理解

递归,我的理解就是一个循环的闭包,而闭包就是在内存中保留某个对象的状态(你也可以理解为复制),递归就是不断的复制更新自己,直到满足条件。正如你的例子所述,change方法就是一个闭包,当change(arr,iNow+1);被启动时,就形成了一个闭包,复制一次自身状态(对象,值),进入循环,!iNow == num条件下递归调用闭包,再次复制,更新,再进入循环,进入条件....直到满足iNow == num,结束循环,停止调用闭包,也就停止了递归

看别人的不如自己思考总结一个,只要自己想出来一次,以后的基本都会有思路。
问题: 有一个100个台阶的阶梯,一次可以选择上一个台阶,或者两个台阶,最后上到楼梯顶有几种走法?
你自己试着解答一下,

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题