算法图解第三章笔记与习题(递归)

算法图解第三章笔记与习题(递归)



3.1 递归

def factorial(x):    # 用递归计算阶乘,可读性更强,但实际性能与循环相同,甚至更差。
    if x == 0 or x == 1:
        return 1
    else:
        return x * factorial(x-1)

递归只是让解决方案更加清晰,但实际上,并没有性能上的优势。


3.2 基线条件和递归条件

编写递归函数时,必须告诉它何时停止递归。

正因为如此,每个递归函数都有两部分:

  • 基线条件(base case):函数不再调用自己,从而避免无限循环。
  • 递归条件(recursive case):函数继续调用自己。

如此,递归函数就会按照我们的预期的那样运行。

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

3.3 栈

**栈(stack)**是一种简单的数据结构,只有压入和弹出两种操作(先进后出)。

3.3.1调用栈

def greet2(name):
    print("how are you, " + name + "?")
def bye():
    print("ok bye!")
def greet(name):
    print("hello, " + name + "!")
    greet2(name)
    print("getting ready to say bye...")
    bye()

上述即是一个栈的体现,其整体调用流程如下:

假设调用greet("Mars"),计算机将首先为该函数调用分配一块内存。

在该内存中,变量name被设置为Mars,并被存储到内存中。

接下来,打印出hello, Mars,再调用greet2("Mars")。同样,计算机也为这个函数调用分配一块内存。

计算机使用一个栈来表示这些内存块,其中第二个内存块位于第一个内存块上面。你打印 how are you, Mars?,然后从函数调用返回。此时,栈顶的内存块被弹出。

现在,栈顶的内存块是函数greet的,这意味着返回到了函数greet。当在调用函数greet2时,函数greet只执行了一部分。即:**调用另一个函数时,当前函数暂停并处于未完成状态。**该函数的所有变量的值都还在内存中。执行完函数greet2后,回到函数greet,并从离开的地方开始接着往下执行:首先打印getting ready to say bye...,再调用函数bye

在栈顶添加了函数bye的内存块。然后,打印ok bye!,并从这个函数返回。

现在又回到了函数greet。由于没有别的事情要做,就从函数greet返回。这个栈用于存储多个函数的变量,被称为调用栈


3.3.2 递归调用栈

递归函数运行时,正需要调用栈。栈在递归中扮演着重要的角色。

以开头的factorial(x)为例,当输入参数x=3时,其递归调用栈如下。

在递归函数运行时,递归函数本身将被一次又一次地调用,不断地先前的前递归函数压入栈中,直到参数达到基线条件并得出返回值后被弹出栈,则先前的一系列的递归函数也将获得返回值并被弹出栈,运行其余被压入栈的递归函数。

使用栈虽然很方便,但是也要付出代价:存储详尽的信息可能占用大量的内存。每个函数调用都要占用一定的内存,如果栈很高,就意味着计算机存储了大量函数调用的信息。在这种情况下,你有两种选择。

  • 重新编写代码,转而使用循环。
  • 使用尾递归

3.4 小结

  • 递归指的是调用自己的函数。
  • 每个递归函数都有两个条件:基线条件和递归条件。
  • 栈有两种操作:压入和弹出。
  • 所有函数调用都进入调用栈。
  • 调用栈可能很长,这将占用大量的内存。

练习

习题3.1
  • 根据下面的调用栈,你可获得哪些信息?(函数在3.3节处)

调用了函数greet,并将参数name的值指定为maggie。而greet函数调用了greet2,并将greet2中的name参数也指定为maggie。此时greet处于未完成状态,等待greet2函数运行完成后,greet函数将继续运行。


习题3.2
  • 假设你编写了一个递归函数,但不小心导致它没完没了地运行。正如你看到的,对于每次函数调用,计算机都将为其在栈中分配内存。递归函数没完没了地运行时,将给栈带来什么影响?

栈将会没完没了地拓展,直到内存地址不足为止(栈溢出)。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值