《计算之魂》读书笔记——第2章,从递推到递归

我们人类的固有思维方式常常是出于直观的,由近及远、从少到多,这样的思维方式让我们很容易理解具体的事物,却也限制了我们的抽象思维,所以当我们理解远离我们生活经验的事物时,就容易出现障碍。我们人类这种自底向上、从小到大的正向思维,称为“递推思维”。但是“计算思维”则不同,它是一种自顶向下、先全局后局部的逆向思维方式,被称为“递归思维”。作为计算机工程的从业者,我们经常需要从递推思维中抽离出来,转换到计算思维,这就需要我们能够很好地应用递归思想。

相对于我们固有的递推思维,递归思维有两个明显的优势。第一个是,只要解决当前一步的问题,就能解决全部的问题;第二个是,剩余的问题,复制处理当前问题的同一过程即可。当然,这里有两个前提条件:(1) 每一个问题在形式上都是相同的,否则无法通过同一个过程完成不同阶段的计算;(2) 必须有一个结束条件。

虽然在多年前已经接触过递归思想,但当时并没有get到它的妙处,而且还颇以为难以理解,只是应付任务式的使用。现在来读吴军老师的这本书,竟然有种相见恨晚的感觉,边读边不由自主地动手写起代码来了。写都写了,那就来复现两个书中的例题吧。

例题1: 上台阶问题

从第0级开始,每次上1或2级台阶,上到第20级,有多少种走法?

这个题如果从正向递推考虑,其实挺难的,很快思维就乱了。那我们试试用递归的方式来解决。

假定到第20级台阶有F(20)种不同的路径,那么到20之前,按照题目的说法,有1级和2级两种走法,也就是F(20) = F(19) + F(18),以此类推,每个当前台阶的上一步,都有两种走法。所以我们就可以给出一个普遍公式:F(n) = F(n-1) + F(n-2),其中,F(1) = 1, F(2) = 2,(这是因为,到第一级台阶只有1种走法,到第二级台阶有两种走法)。

 上代码,为了简单,用Python实现的。

def func(n):
    assert(n >= 1)
    if n == 1:
        return 1
    elif n == 2:
        return 2
    else:
        return func(n - 1) + func(n - 2)


print("func(20) = ", func(20)) 

运行结果:

func(20) =  10946 

与书上的结果一致。

再来看第二个问题,汉诺塔问题。

例题2:汉诺塔问题

有三根柱子,A、B、T。A柱子上有N个盘子,其中,小盘子必须放在大盘子的上面。按照下面规则把所有盘子从A柱子移到B柱子:

1. 每次只能移动一个盘子;

2. 任何时候小盘子都不能放在大盘子下面;

3. T柱可以用来临时存放盘子,但盘子的次序也不能违反第2条规则。

N=1的时候比较直观,直接将唯一的盘子从A柱移到B柱即可;

N=2的时候也比较简单,先把第一个盘子(最上面的小盘子)从A柱放到T柱,再把第二个盘子(下面的大盘子)从A柱移到B柱,最后把T柱上的小盘子再放到B柱上。

N>=3的时候,就越来越复杂了。

所以接下来,我们还是应用递归思想,要移动最下面的第N个盘子,必须先把上面的N-1个盘子移动到T柱;移动完第N个盘子之后,还要把T柱上的N-1个盘子借助A柱再移动到B柱。重复这个过程,一直到完成移动。

继续上代码:

# Move n dishes from A to B, with T is a middle transfer
# The bigger dishes must be placed under the smaller ones in each column
def Hanoi(n, A, B, T):
    if n > 0:
        Hanoi(n-1, A, T, B)
        print('move dish {} from {} to {}'.format(n, A, B))
        Hanoi(n-1, T, B, A)


Hanoi(4, 'A', 'B', 'T')

 简单起见,测试了1~5个盘子的移动,其中,4个盘子的移动顺序如下:

《计算之魂》读书笔记——第2章,从递推到递归_第1张图片

是不是简洁又完美!

你可能感兴趣的:(读书笔记,算法)