Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于递归及优化 #9

Open
heycn opened this issue May 10, 2023 · 0 comments
Open

关于递归及优化 #9

heycn opened this issue May 10, 2023 · 0 comments

Comments

@heycn
Copy link
Owner

heycn commented May 10, 2023

递归例子

阶乘

j = n => n === 1 ? 1 : n * j(n-1)

斐波那契数列

fib = n =>
  n === 0 ? 0 :
  n === 1 ? 1 :
  fib(n-1) + fib(n-2)

注意:每次进入函数需要往 调用栈 里「压栈」,调用栈 用来记录「回到哪」,如果需要记录得过多,就会「爆栈」。

所以,需要降低「压栈」或者计算次数,以下是优化方案

优化手段

尾递归优化

使用迭代代替递归

fib = n => fib_inner()

fib_inner = (start, end, prev1, prev2) =>
  start === end ? prev1 + prev2
    : fib_inner(start+1, end, prev1+prev2, prev1)

这就是「尾递归」

为什么尾递归可以优化?因为不用「压栈」了,「压栈」的目的是为了记录回到哪,那如果我不回来,那我就不需要「压栈」了。

注意:但是!JS 有 Bug,就算你不压栈,它还是会把一些不相关的操作压进去(例如环境),所以,JS 不存在「尾递归优化」!
所以,以上代码,依然会「压栈」,虽然会快一些,但是没有什么区别。

改写成循环

所有的递归都可以改写成循环

fib_loop = n => {
  let array = [0, 1]
  for(let i = 0; i <= n-2; i++) {
    array[i+2] = array[i+1] + array[i]
  }
  return array[array.length-1]
}

以上代码把结果都记录在数组里面,那么就不需要重复的计算某些值了。

以下是 ChatGPT 对以上代码的解释:

以上代码是一个计算斐波那契数列第 n 项的函数,采用了循环方式来计算。具体解释如下:

1. `fib_loop = n => {...}`:定义一个名为 `fib_loop` 的函数,它接受一个参数 `n`,使用箭头函数方式定义。
2. `let array = [0, 1]`:初始化一个数组 `array`,它包含斐波那契数列的初始两个元素。
3. `for(let i = 0; i <= n-2; i++) {...}`:循环遍历 `array` 数组,从第3项开始依次计算出斐波那契数列的每一项,直到计算出第n项。
4. `array[i+2] = array[i+1] + array[i]`:计算斐波那契数列的每一项,并存储在 `array` 数组中。
5. `return array[array.length-1]`:返回 `array` 数组的最后一项,也就是斐波那契数列的第 n 项。

递归好像没什么用?

使用循环就能解决,这样看起来递归很无用呀?是的,有时候递归就是这样。

因为 JS 在递归方面就没有提供很好的工具,所以在 JS 中写递归会让你的同事看不懂,并且性能又差,那怎么办呢?

使用「记忆化」 —— 这是一个很好的解决办法。

记忆化

如果我曾经算过了,那就不要算了

可以减少重复计算,大大减低压栈次数

以下是 Lodash 记忆化函数的实现:lodash/memoize.js

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant