递归是一种解决问题的方法,它从解决问题的各个小部分开始,直到解决最初的大问题.递归通常涉及函数调用自身.
下面通过例子来说明.
一.计算一个数的阶乘
作为递归的第一个例子,来看下如何计算一个数的阶乘.数n的阶乘,定义为n!,表示从1到n的整数的乘积.
5的阶乘表示为5!,和5*4*3*2*1相等,结果是120.
(1)迭代阶乘
如果尝试表示计算任意数n的阶乘的步骤,可以将步骤定义如下:(n)*(n-1)*(n-2)*(n-3)*...*1 .
可以使用循环来写一个计算一个数阶乘的函数,如下所示:
function factorialIterative(number) {
if (number < 0) return undefined
let total = 1
for (let n = number; n > 1; n--){
total = total * n
}
return total
}
console.log(factorialIterative(5));
最后输出结果是120.
我们可以从给定的number开始计算阶乘,并减少n,直到它的值为2,因为1的阶乘还是1,而且它已经被包含在total变量中了.零的阶乘也是1.负数的阶乘不会被计算.
(2)递归阶乘
现在我们试着用递归来重写factorialIterative函数.
function factorial(n) {
if (n === 1 || n === 0) {//基线条件
return 1
}
return n * factorial(n - 1)//递归调用
}
console.log(factorial(5))//120
二.斐波那契数列
斐波那契数列是另一个可以用递归解决的问题.它是一个由0,1,1,2,3,5,8,13,21,34等数组成的数列.数2由1+1得到,数3由1+2得到,数5由2+3得到,以此类推,斐波那契数列的定义如下:
位置0的斐波那契数列是零;
1和2的斐波那契数是1;
n(此处n>2)的斐波那契数是是(n-1)的斐波那契数加上(n-2)的斐波那契数.
(1)迭代求斐波那契数
我们用迭代的方式实现了fibonacci函数,如下所示:
function fibonacciIterative(n) {
if (n < 1) return 0
if (n <= 2) return 1
let fibNMinus2 = 0
let fibNMinus1 = 1
let fibN = n
for (let i = 2; i <= n; i++) {//n >=2
fibN = fibNMinus1 + fibNMinus2//f(n-1)+f(n-2)
fibNMinus2 = fibNMinus1
fibNMinus1 = fibN
}
return fibN
}
(2)递归求斐波那契数
fibonacci函数可以写成这样:
function fibonacci(n) {
if (n < 1) return 0
if (n <= 2) return 1
return fibonacci(n - 1) + fibonacci(n - 2)
}
(3)记忆化斐波那契数
还有第三种写fibonacci函数的方法,叫做记忆法.记忆法是一种保存前一个结果的值的优化技术,类似于缓存.如果我们分析在计算fibonacci(5)时的调用,会发现fibonacci(3)被计算了两次,因此可以将它的结果存储下来,这样当需要再次计算它的时候,我们就已经有了它的结果了.
下面的代码展示了使用记忆化的fibonacci函数:
function fibonacciMemoization() {
const memo = [0, 1]
const fibonacci = (n) => {
if (memo[n] !== null) return memo[n]
return memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo)
}
return fibonacci
}
在上面代码中,我们声明了一个memo数组来缓存所有的计算结果.如果结果已经被计算了,我们就返回它,否则计算该结果并将它加入缓存.