汉诺塔游戏

前天在一次面试中,面试官问到我汉诺塔(Towers of Hanoi)的问题,当时只知道是递归,知道手动玩游戏怎么玩,写程序还真的忘记了。大学我记得是有写过这样的作业,还有八皇后等等,不过真的都还给老师了,哈哈哈!

然后回家看了下,
http://www.cs.cmu.edu/~cburch/survey/recurse/hanoiimpl.html
http://www.python-course.eu/towers_of_hanoi.php

汉诺塔的介绍参见http://en.wikipedia.org/wiki/Tower_of_Hanoi等等

程序如下,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
 
void move(char src, char dest)
{
    printf("\nMove the top plate of %c to %c", src, dest);
}
 
void hanoi(int n, char a, char b, char c)
{
    if (n == 1) { // 递归结束
        move(a, c); // 最小的那个盘子
    } else {
        hanoi(n - 1, a, c, b); // step 1,把所有小于最大的盘子移动到临时的柱子上(可以借助目的柱子)
        move(a, c); // step 2,把最大的盘子移动到目的柱子上
        hanoi(n - 1, b, a, c); // step 3,把临时的柱子上的盘子移动到目的柱子上(可以借助原始柱子),和step 1的方式一模一样
 
                            // step 1和3都会有递归产生
    }
}
 
int main()
{
    int n;
    printf("\nPlz input number of the plates:");
    scanf("%d", &n);
    printf("\nMoving %d plates from A to C:", n);
 
    hanoi(n, 'A', 'B', 'C');
 
    printf("\nDone!\n");
}

如果你能看懂上面的注释,很好。如果你看不懂,也没关系,现在我们来试着详细点解释这个问题。
我们先来玩这个游戏,如图(点击图片看正常大图),
Towers of Hanoi
你会发现盘子的数量和最终要花费的步数是有关系的,为2^n – 1,也就是说只有1个盘子的时候需要1步,2个盘子的时候需要3步,3个盘子的时候需要7步,以此直到天荒地老。。。

所以这种思路我们是不是可以采用递归那完成呢?
比如3个盘子的时候,我们先移动上面的2个盘子(需要3步),再移动最大的1个盘子(需要1步),然后再移动那2个盘子到最大的盘子上面(需要3步),加起来一共就是7步,刚刚好。
并且2个盘子也可以同理拆分,最终会变成1个盘子的情况,1个盘子的情况很好解决,就1步,别且这也就是边界情况。

看起来这样是可以,再回头来看看程序,
step 1 ~ 3是不是很清晰了,并且step 1和3自己又会有递归产生,继续拆分,直到最后都是1个盘子的时候,递归结束。

如果不关心内部细节是不是就这样完美结束了呢?确实,如果你不关心内部细节,这样已经让人很容易的理解这个问题。但是总归会有一部分人会继续深挖。
现在我们以3个盘子为例,以程序执行的角度来看,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
hanoi(3, 'A', 'B', 'C')
{
    hanoi(2, 'A', 'C', 'B');
        hanoi(1, 'A', 'B', 'C')
            move('A', 'C')
        move('A', 'B')
        hanoi(1, 'C', 'A', 'B')
            move('C', 'B')
    move('A', 'C');
    hanoi(2, 'B', 'A', 'C');
        hanoi(1, 'B', 'C', 'A')
            move('B', 'A')
        move('B', 'C')
        hanoi(1, 'A', 'B', 'C')
            move('A', 'C')
}

好像也没什么好写的,有机会看看非递归的方式来实现。

P.S.
递归有风险,使用需谨慎!

Leave a Reply

Your email address will not be published. Required fields are marked *