汉诺塔游戏

前天在一次面试中,面试官问到我汉诺塔(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等等

程序如下,

#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个盘子为例,以程序执行的角度来看,

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 *