【算法图解】读书笔记:第3章 递归

递归


在我看来,递归就相似俄罗斯套娃,一次次重复去执行相同的操做,最后得出结果的过程。算法

不少递归的操做均可以使用循环来替代。递归并无带来算法性能上的优点,甚至更差,可是使用递归可能让你的程序更易理解。因此理解递归这种概念很重要。编程

基线条件和递归条件


因为递归函数调用本身,很容易致使无线循环。好比,你须要一个倒数的函数:bash

def countdown(i):
  print(i)
  countdown(i - 1)

countdown(3)
复制代码

若是运行上述代码,这个函数就会不停的运行。函数

编写递归函数式,必须告诉它什么时候中止递归,性能

每一个递归函数都有两部分:基线条件(base case)和递归条件(recursive case)。递归条件指的是函数调用本身,而基线条件则 指的是函数再也不调用本身,从而避免造成无限循环。优化

好了,咱们尝试为上面的代码增长基线条件:ui

def countdown(i):
  print(i)
  if i <= 0: # 基线条件
    return
  else: # 递归条件
    countdown(i - 1)

countdown(3)
# 3 2 1 0 程序中止
复制代码


调用栈不只对于编程来讲很重要,使用递归是也必须裂解这个概念。计算机在内部使用被称为调用栈的栈。spa

咱们简单看一个例子:code

# 忽略 print 这个函数带来的影响
# 开始执行函数 greet ,此时内存中开辟一块空间 greet 进入栈中
def greet(name):
  # 在 greet 的内存中,添加变量name
  print "hello, " + name + "!"
  # 开始执行 greet2 ,此时内存中开辟空间 greet2,greet2 入栈
  # greet <-- greet2 相似这种链式结构
  greet2(name)
  # greet2 执行完毕,出栈
  # greet
  print "getting ready to say bye..." 
  # 开始执行bye ,此时内存中开辟空间 bye,bye 入栈
  # greet <-- bye
  bye()
  # bye 执行完毕,出栈
  # greet
# 最后greet执行完毕,出栈
复制代码

栈的执行逻辑就是:先进后出原则。递归

递归调用栈


递归调用中,存储详尽的信息可能占用大量的内存。这回付出很大的代价。若是占用太高,你须要使用循环去代替递归,或者使用尾递归优化,前提是你的语言支持尾递归优化。

小结


  • 递归指的是调用本身的函数。
  • 每一个递归函数都有两个条件:基线条件和递归条件。
  • 栈有两种操做:压入和弹出。
  • 全部函数调用都进入调用栈。
  • 调用栈可能很长,这将占用大量的内存
相关文章
相关标签/搜索