斐波那契数列:0,1, 1, 2, 3, 5, 8,13,21…
- 第一种递归写法
- 弊端:50往后超级慢
function fibonacci (n) {
if (n === 1) {
return 0
} else if (n === 2) {
return 1
} else {
return fibonacci(n-1) + fibonacci(n-2)
}
}
- 第二种写法
- 弊端:没有弊端,100个都非常快,甚至可以打印出前n个组成的对象
function fibonacci (n) {
let obj = {
1: 0,
2: 1,
}
for (let i = 3; i <= n; i++) {
obj[i] = obj[i-1] + obj[i-2]
}
console.log(obj)
return obj[n]
}
- 这是我从一个例子中延伸出来的,就是说通过一种简单算法获取一个文件夹中的所有文件,当然这个文件夹中可能有文件夹,文件夹的文件夹中可能还有文件夹…,在通过递归实现以后,试着通过其他的方法实现一下,来验证一种猜想,就是递归转循环的可能性。
- 但是一搜递归转循环,很多人都是拿斐波那契数来举例子。
- 个人认为这两个例子中有很大不同,递归求fibonacci是因为重复运算的问题,会导致多走弯路。是属于上层数据对下层数据有依赖的情况。
- 但是文件夹的问题不是,是需要把每一个文件夹都打开才能知道里面是有文件夹,还是全是文件,递归并不会多走哪怕一条路。
- 而且fibonacci是知道唯一的开始在哪,同时也知道结束在哪(就是n),可以选择从下往上走,来解决重复运算的问题。
- 但是文件夹的问题却是没有唯一的尽头的,因为可能存在很多个尽头,每一个只包含文件的文件夹都是一个尽头。而且每一个文件夹中的文件夹又是一个新的开始。并不存在对上层或下层依赖问题。
总结:
- 递归写起来好些,也好理解,但是执行起来不一定好用
- 不是所有的递归都可以转换成循环
- 对于只有一个开始和一个尽头的问题,可以通过循环来替换递归,缺一不可
关于递归和循环的另一个问题(性能vs栈内存)比较,见另一篇
相比于循环,递归的缺陷