cs61a 第三周课时笔记-令人惊讶的递归实现!

本周笔记迭代、递归和树递归

iteration

Fibonacci数列

首项为0,第一项为1,接下来每项的值等于其前两项之和。
定义一个函数,返回Fibonacci数列第n项的值:

def fib(n):
    """computer the nth Fibonacci number.
    
    >>> fib(0)
    0
    >>> fib(8)
    21
    """
    
    k, kth, diff = 0, 0, 1
    while k < n:
        kth, diff = kth + diff, kth
        k = k + 1
    return kth

返回值

逆序打印一个给定整数每个位数上的数,直到找到指定的数

def end(n, d):
    """
    
    >>> end(45678, 4)
    8
    7
    5
    4
    """
    while n > 0:
        last, n = n % 10, n // 10
        print(last)
        if d == last:
            return None

end(45678, 5)

自调用

3-1
使用函数print_sums(1)(3)(5)时,先执行print_sums(1),返回值是其内部定义的一个函数,此时函数没有执行。当执行rint_sums(1)(3),执行的函数是next_sum(3), 返回的是print_sums(3+1)的结果:函数print_sums。此时局部环境中n=4,执行print_sums(1)(3)(5)就是执行next_sum(5), 返回的是print_sums(4+5)的结果:函数print_sums。

recurrsion

例子:整数各位上的数之和

一个整数能被9整除,那么该整数各位上的数之和能被9整除,如2016被9整除,2+0+1+6 = 9能被9整除。可以将2016拆分两部分201各位上的和与6的和。201又能拆分为20、1.
3-2
递归调用结束条件满足时,即base case满足时,递归结束。base case的return在整个递归执行过程之只执行一次。
online python tutor 调试
3-3

递归环境框图

递归调用时的框图:
3-4
每次递归调用都不会马上返回当前环境的最终结果,只有当递归终结条件满足时,从最后的调用开始,一次向上返回结果。

迭代和循环

3-5
迭代是递归的一种特殊形式。
使用while迭代式需要多个变量追踪数据的变化;而是用递归需要开辟更多的内存空间去追踪每个局部环境的变量。

如何保证递归正确执行

3-6
这里计算阶乘,类似数学归纳法。
递归调用中,一定要保证递归终止条件是能够被满足的。

将递归和迭代相互转化

3-8

3-7

递归调用顺序

实现一个堆叠功能

输入12345
输出:
12345
1234
123
12
1
12
123
1234
12345
3-8
递归调用中,当不满足递归停止条件时,打印输入参数n,停止调用之前,函数cascade之后的print都不会执行。递归调用第二次时,及执行到上图框图f3时,cascade函数才被真正执行完一次,返回None,然后回到框图f2执行下一句print(n),此时f2执行完毕,回到f1,执行下一句print(n)。

堆叠输出的两种定义方式

3-9

反向堆叠

输入:1234
输出:
3-10
通过一个lambda函数递归调用grow和shrink函数。

在线调试:online python tutor

Tree recurrsion

使用递归实现Fibonacci数列

3-11
这种实现方式有一个问题,那就是n以前的项总是被重复计算。计算fib(3)时需要计算fib(2),fib(1),计算fib(2)又要计算fib(1), fib(0)。每次计算fib(m), 比他更小的项总是重新计算。
3-12

使用trace追踪递归调用过程

# Decorators
def mytrace(fn):
    """Return a function equivalent to fn that also prints trace output.

    fn -- a function of one argument.
    """
    def traced(x):
        print('Calling', fn, 'on argument', x)
        return fn(x)
    return traced
    

@mytrace
def fib(n):
    """Compute the nth Fibonacci number.

    >>> fib(8)
    21
    """
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fib(n-2) + fib(n-1)
        
fib(5)

3-13
上图打印的递归调用过程和ppt上的树节点的结算顺序一致。

计算一个正整数的所有可能正加数组合的个数。

比如计算和为6的加数中,小于等于4的所有加数组合数。
3-14
分为两种情况考虑,包括给定数的情况和不包括给定数的情况。在count_partitions(6,4)这个例子中,第一个count_partitions(n-m, m)中n-m是计算余数6-4=2是否还可分,就如树一样,从顶往下搜索。递归结束条件if n==0 和 if n<0返回是否存在。转为代码:
3-15
使用trace追踪递归过程:

def mytrace(fn):
    """Return a function equivalent to fn that also prints trace output.

    fn -- a function of one argument.
    """
    def traced(x, y):
        print('Calling', fn, 'on argument', x, y)
        return fn(x, y)
    return traced
    

@mytrace
def count_partitions(n, m):
    """Count the partitions of n using parts up to size m.

    >>> count_partitions(6, 4)
    9
    >>> count_partitions(10, 10)
    42
    """
    if n == 0:
        return 1
    elif n < 0:
        return 0
    elif m == 0:
        return 0
    else:
        with_m = count_partitions(n-m, m)
        without_m = count_partitions(n, m-1)
        return with_m + without_m


count_partitions(4, 4)

在线调试,调试结果:
3-14

参考:
https://www.bilibili.com/video/BV16W411W76H?p=46
https://inst.eecs.berkeley.edu/~cs61a/sp18/
http://composingprograms.com/pages/17-recursive-functions.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章