学习js数据结构与算法-递归

171 阅读2分钟

这是我参与2022首次更文挑战的第26天,活动详情查看:2022首次更文挑战」。

个人觉得要想进大厂,就必须学习了解算法和数据结构,经历了多次面试之后,也知道了算法和数据结构的重要性,所以,我也打算从今天开始,进入学习,下载了一下电子书,边看书,边跟着书的例子来敲一下代码,下面就开始总结一下对算法和数据结构的学习吧。

第二十六天:学习递归

递归

在学习树和图数据结构之前,我们先了解递归,让之后的学习边得更简单

递归是一个种解决问题的方法,从解决小问题开始,直到解决最初的大问题。递归通常设计函数自调用。

计算一个数的阶乘

  • 如果不使用递归

    function factorialIterative(number) {
      if(number < 0) return undefined
      let total = 1
      for(let i = number; i > 0; i--) {
        total *= i
      }
      return total
    }
    
    

    首先是合法性判断,然后进行循环,循环次数是传入的参数,计算出总值。

  • 使用递归

    function factorial(n) {
    	if(n === 1 || n === 0) {
        return 1
      }
      return n * function(n - 1)
    }
    

    如果传入的是1或者是0,返回1,否则继续调用自身,参数传入n-1,乘以n。

    调用栈

    前面我们学了栈结构,递归就是使用它的例子,每当一个函数被调用时,该函数就会进入调用栈的顶部,每当使用时,就会从栈顶移除。

    用浏览器查看调用栈的行为

image-20220222005756087.png

在return 1 那里打上断点,可以看到Call Stack上有五个factorial函数的调用,如果一个个往下走的话,会看到Call Stack开始弹出factorial的调用。

js调用栈大小的限制

如果递归没有结束条件,就会一直执行下去,然后浏览器就会抛出错误(stack overflow error)

根据操作系统和浏览器的不同,具体执行次数会有所不同,但区别不大。

斐波那契数列

它是一个由 0、1、1、2、3、5、8、13、21、 34等数组成的序列

  • 不使用递归

    function fibonacciIterative(n) {
      if(n < 0) return 0
      if(n <= 2) return 1
      let f1 = 0, f2 = 1, fx
      for(let i = 2; i < n; i++) {
        fx = f1 + f2
        f1 = f2
        f2 = fx
      }
      return fx
    }
    

    先初始化前两个值,然后进入循环,fx是一个中间值,将f1和f2相加给这个中间值,然后移动f1的位置,将fx的值给f2

  • 使用递归

    function fibonacci(n) {
      if(n < 1) return 0
      if(n === 1 || n === 2) {
        return 1
      }
      return fibonacci(n) + fibonacci(n - 1)
    }
    

    可以用下图解释上面的调用过程

image-20220222011338785.png

  • 记忆化斐波那契数

    可以看到上面的执行,fibonace(3)执行了两次,因此可以将它的结果存起来,当需要再次计算它的时候,直接使用它的结果

    function fibonacciMemoization(n) {
      const memo = [0, 1];
      const fibonacci = (n) => {
        if (memo[n] != null) return memo[n]; 
        memo[n] = fibonacci(n - 1) + fibonacci(n - 2)
        return memo[n]
      }
      return fibonacci
    }
    

为什么使用递归

使用递归并不是说它执行得更快,但递归版本更容易理解,通常代码也更少。