[TOC]
js 优化递归使用尾调用优化
>[success] # 递归阶乘
~~~
1.求5*4*3*2*1 的问题,用递归来解决三步走
1.1.分解成各个小部分
5 * fn(4) 参数n = 5-1
5 * (4*fn(3)) 参数n = 4-1
5 * 4 * (3*fn(2)) 参数n = 3-1
5 * 4 * 3 * (2*fn(1)) 参数n =2-1
1.2.推到成递归公式 fn(n) = n*fn(n-1) ,且fn(1) = 1
1.3.终止条件 fn(1) = 1
~~~
>[danger] ##### 代码
~~~
1.递归是栈的结构表现,所以它'递'的过程是在做压栈,'归'的过程在做出栈,其实本质,先算的是
终止条件,然后在依次向上传递
2.如图一,通过浏览器的控制台可以更形象的看出这个过程
~~~
~~~
// 递归阶乘 求 5*4*3*2*1
// 先拆分 5 * fn(4) 参数n = 5-1
// 5 * (4*fn(3)) 参数n = 4-1
// 5 * 4 * (3*fn(2)) 参数n = 3-1
// 5 * 4 * 3 * (2*fn(1)) 参数n =2-1
// 现在就是一个压栈的过程,从5*fn(4)先进,依次压栈直到最后 fn(1),执行的时候
// 出栈时候从fn(1) 开始执行,因此为什么要有终止条件也可以理解了
function factorial(n){
console.trace()
// 记录堆栈
// 归的过程 -- 墙相当于 乘到了1
if(n===1 || n===0){
return 1
}
console.log(n)
// 调用 -- 传递的过程
return n * factorial(n-1)
}
factorial(5)
~~~
* f12 打断点也可发现遵循栈的思路先进后出
![](https://img.kancloud.cn/bc/2e/bc2e4951661c0ceb3bf1719ac85f836b_1622x333.png)
* 运行图解
![](https://img.kancloud.cn/d2/71/d2711db57e2cd0c2a1f4322c1b81aa35_428x170.png)
>[success] # 斐波那契数列
~~~
0,1,1,2,3,5,8,13,21
~~~
>[danger] ##### 不用递归
~~~
// 斐波那契数列
function fibonacciIterative(n){
if(n < 1) return 0
if(n <=2) return 1
let fib2 = 0
let fib1 = 1
let fibN = 0
for(let i =3;i<=n;i++){
fibN = fib1 + fib2
fib2 = fib1
fib1 = fibN
}
return fibN
}
~~~
>[danger] ##### 使用递归
~~~
// 斐波那契数列
function fibonacciIterative(n){
if(n < 1) return 0 // 结束条件
if(n <=2) return 1 // 结束条件
return fibonacciIterative(n-2) + fibonacciIterative(n-1) // 递归公式 fn(n) = fn(n-1)+fn(n-2)
}
~~~
>[success] # 减少重复递归 -- 记忆化方法
~~~
1.向求解斐波那契数列时候,将求解过程图形化,可以看出,有些已经
求过的结点我们还会反复在求,如果把这些一求过的数存起来直接用,也会
提高效率
~~~
![](https://img.kancloud.cn/12/67/12676600dab45a583fcaf30cf67a86ec_1142x837.png)
>[danger] ##### 代码
~~~
function fibonacciMemoization(n) {
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(n);
}
~~~
- 接触数据结构和算法
- 数据结构与算法 -- 大O复杂度表示法
- 数据结构与算法 -- 时间复杂度分析
- 最好、最坏、平均、均摊时间复杂度
- 基础数据结构和算法
- 线性表和非线性表
- 结构 -- 数组
- JS -- 数组
- 结构 -- 栈
- JS -- 栈
- JS -- 栈有效圆括号
- JS -- 汉诺塔
- 结构 -- 队列
- JS -- 队列
- JS -- 双端队列
- JS -- 循环队列
- 结构 -- 链表
- JS -- 链表
- JS -- 双向链表
- JS -- 循环链表
- JS -- 有序链表
- 结构 -- JS 字典
- 结构 -- 散列表
- 结构 -- js 散列表
- 结构 -- js分离链表
- 结构 -- js开放寻址法
- 结构 -- 递归
- 结构 -- js递归经典问题
- 结构 -- 树
- 结构 -- js 二搜索树
- 结构 -- 红黑树
- 结构 -- 堆
- 结构 -- js 堆
- 结构 -- js 堆排序
- 结构 -- 排序
- js -- 冒泡排序
- js -- 选择排序
- js -- 插入排序
- js -- 归并排序
- js -- 快速排序
- js -- 计数排序
- js -- 桶排序
- js -- 基数排序
- 结构 -- 算法
- 搜索算法
- 二分搜索
- 内插搜索
- 随机算法
- 简单
- 第一题 两数之和
- 第七题 反转整数
- 第九题 回文数
- 第十三题 罗马数字转整数
- 常见一些需求
- 把原始 list 转换成树形结构