递归概念

递归是一种针对简单循环难以编程实现的问题,通过函数调用自身,提供优雅解决方案的技术。

递归都具有以下三个要点:

  • 使用 if-else 或 switch 语句来引导不同的情况。

  • 拥有基础情况(base case)或终止条件(stopping condition)来停止递归。

  • 每次递归调用都会简化原始问题,让它不断接近基础情况,所以可以用不同的参数调用自身方法,直到它变为这种基础情况。这个称之为递归调用(recursive call)。

示例,计算阶乘

if(n == 0){ // base case
  return 0;
}else { // recursive call
  return n * factorial(n-1)
}

递归的优势--斐波那契数列

计算阶乘很容易使用循环改写,某些情况下,用循环不容易解决的问题可以利用递归给出一个直观简单的解法。

斐波那契数列从 0 到 1 开始,之后的每个数都是序列中的前两个数之和,通过递归可以简单的实现出来。

var count = 0;

function fib(n) {
    count++;
    if(n == 0){
        return 0;
    }else if(n == 1){
        return 1;
    }else {
        return fib(n-1) + fib(n-2);
    }
}

const result = fib(10);

console.log('result',result);
console.log('count',count);
// result 55
// count 177

程序中会出现很多重复调用,求第 10 个斐波那契数,就调用了 177 次自身函数,如果尝试求出更大的斐波那契数,那么相应的调用次数就会急剧的增加。

优化递归调用

将计算过的斐波那契值存起来,可以优化递归调用。通过改良,求第 10 个斐波那契数,只调用的 11 次自身函数。而且调用自身函数的次数永远是,n + 1 次,n 代表第 n 个需求的斐波那契数。

var count = 0;
const calculated = [];

function fib(n) {
    count++;

    if(n == 0){
        return 0;
    }else if(n == 1){
        return 1;
    }else {
        if(!calculated[n-1]){
            calculated[n-1] = fib(n-1);
        }

        if(!calculated[n-2]){
            calculated[n-2] = fib(n-2);
        }
        return calculated[n-1] + calculated[n-2];
    }

}

const result = fib(10);

console.log('result',result);
console.log('count',count);
// result 55
// count 11

递归辅助方法

有时候可以通过找到一个要解决的初始问题的类似问题,来找到初始问题的解决方案。这个类似的方法称之为递归辅助方法。

举例,如果一个字符串从左读和从右读都是一样的,那么他就是一个回文串(palindrome)。可以通过下面的函数判断。

function palindrome(str) {
    if(str.length <= 1 ){
        return true;
    }else if(str[0] !== str[str.length - 1]){
        return false;
    }else {
        return palindrome(str.slice(1,-1));
    }
}

const result = palindrome("dddddd");

console.log(result); // ture

每次调用 palindrome 方法时,都会使用 str.slice 来创建一个新的字符串。
为了避免重新创建字符串,使用递归辅助方法 isPalindrome 来进行改良。

function isPalindrome(str) {
    return palindrome(str,0,str.length-1);
}

function palindrome(str,low,high) {

    if(low >= high){
        return true;
    }else if(str[low] !== str[high]){
        return false;
    }else {
        low ++;
        high --;
        return palindrome(str,low,high);
    }
}

const result = isPalindrome("dddaaaerddd");

console.log(result); // false

fitfish
1.6k 声望950 粉丝

前端第七年,写一个 RN 专栏。