当前位置:嗨网首页>书籍在线阅读

04-基线条件的运用

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

1.1.2 基线条件的运用

请注意,在运行 fib1() 之前,Python运行环境不会有任何提示有错误存在。避免无限递归由程序员负责,而不由编译器或解释器负责。出现无限递归的原因是尚未指定基线条件(base case)。在递归函数中,基线条件即函数终止运行的时点。

就斐波那契函数而言,天然存在两个基线条件,其形式就是序列最开始的两个特殊数字0和1。0和1都不是由序列的前两个数求和得来的,而是序列最开始的两个特殊数字。那就试着将其设为基线条件吧,具体代码如代码清单1-3所示。

代码清单1-3 fib2.py

def fib2(n: int) -> int:
    if n < 2:  # base case
        return n
    return fib2(n - 2) + fib2(n - 1)  # recursive case

注意   斐波那契函数的 fib2() 版本将返回 0 作为第0个数( fib2(0) ),而不是第一个数,这正符合我们的本意。这在编程时很有意义,因为大家已经习惯了序列从第0个元素开始。

fib2() 能被调用成功并将返回正确的结果。可以用几个较小的数试着调用一下,具体代码如代码清单1-4所示。

代码清单1-4 fib2.py(续)

if __name__ == "__main__":
    print(fib2(5))
    print(fib2(10))

请勿尝试调用 fib2(50) ,因为它永远不会终止运行!每次调用 fib2() 都会再调用两次 fib2() ,方式就是递归调用 fib2(n - 1)fib2(n - 2) (如图1-3所示)。换句话说,这种树状调用结构将呈指数级增长。例如,调用 fib2(4) 将产生如下一整套调用:

fib2(4) -> fib2(3), fib2(2)
fib2(3) -> fib2(2), fib2(1)
fib2(2) -> fib2(1), fib2(0)
fib2(2) -> fib2(1), fib2(0)
fib2(1) -> 1
fib2(1) -> 1
fib2(1) -> 1
fib2(0) -> 0
fib2(0) -> 0

不妨来数一下(如果加入几次打印函数调用即可看明白),仅为了计算第4个元素就需要调用9次 fib2() !情况会越来越糟糕,计算第5个元素需要调用15次,计算第10个元素需要调用117次,计算第20个元素需要调用21891次。我们应该能改善这种情况。

8.png

图1-3 每次非基线条件下的 `fib2()` 调用都会再生成两次 `fib2()` 调用