递归的概述
递归就是指函数调用自身(自己调用自己),使用时必须有终止递归的条件。递归可以根据条件执行重复的业务逻辑代码,类似循环语句,但功能比循环灵活,强大。
JavaScript 中的递归是一种函数调用自身的技术,它允许函数在执行过程中调用自己。递归通常用于解决可以被分解为相似子问题的问题,例如树的遍历、排序算法(如快速排序和归并排序)、计算阶乘、斐波那契数列等。
递归函数通常包含两个部分:
- 递归终止条件(Base Case):这是递归停止的条件,防止无限递归。
- 递归步骤(Recursive Case):这是函数调用自身的部分。
递归的基本语法,其中函数调用自身的方式并不是唯一的,可以作为计算或函数返回值调用自身等。
function foo() {
if (终止条件) {
终止代码
return;
}
// 函数自身调用
foo();
}
递归的示例
定义一个递归函数,用于计算一个数的阶乘。
阶乘的计算公式如下,其中0和1的阶层也是1。
n!=1*2*3*4...*n
1!=0!=1
假设我们需要计算5的阶乘,也就是计算:
5!=1*2*3*4*5
我们可以将它拆分为:
5!=5*4!
4!=4*3!
3!=3*2!
2!=2*1!
1!=1
计算n的阶乘,可以拆分为计算n乘以n-1的阶乘,直到n=1,可以总结为:
n!=n*(n-1)!
factorial
函数调用自己来计算 n - 1
的阶乘,直到 n
等于 0 或 1 时停止递归。这个递归函数的终止条件就是n=1或者n=0,递归的步骤就是n不断的乘以自身-1的阶乘。
function factorial(n) {
// 递归终止条件
if (n === 0 || n === 1) {
return 1;
}
// 递归步骤
return n * factorial(n - 1);
}
console.log(factorial(5)); // 输出:120
再定义一个递归函数,输出函数的执行次数,终止条件是次数>5,函数调用自身,每次都在自身基础上+1并输出。
// 2)递归函数
function loop(num) {
if (num > 5) {
// 终止代码
return;
}
console.log("执行" + num + "次");
// 返回,终止代码
return loop(num + 1);
}
loop(1);
使用递归实现1~50的1+2+...+50累加,封装递归函数,终止条件是n到50,递归的步骤是n+(n+1),传递实参1,实现1到50之间的数字相加。
function add(num) {
if (num >= 50) {
return 50;
}
// 把每次调用add函数传递的num相加
return num + add(num + 1);
}
var v1 = add(1);
console.log("v1:", v1);
如果不希望限制累加的上限(希望从1加到n),可以反过来将上限作为参数进行计算,也就是50+49+...+1,那么终止条件就是n到1,递归的步骤就是n+(n-1)。
function add2(num) {
if (num <= 1) {
return 1;
}
return num + add2(num - 1);
}
var v2 = add2(100);
console.log("v2:", v2);
var v3 = add2(50);
console.log("v3:", v3);
递归函数一定要有终止条件。定义一个递归函数,没有定义终止条件,会报错RangeError:Maximum call stack size exceeded,也就是栈溢出,意思是程序中出现死循环了。
使用递归的注意事项
使用递归时需要注意以下几点:
- 确保递归有明确的终止条件,否则可能导致无限递归。
- 考虑递归的效率,递归可能导致较大的内存消耗和性能问题,特别是当递归深度很大时。
- 递归可能不是所有问题的最佳解决方案,有时迭代方法可能更合适。