#include <stdio.h>
/**
* Hanoi
*/
void hanoi(int paraN, char paraSource, char paraDestination, char paraTransit) {
if (paraN <= 0) {
return;
}
else {
hanoi(paraN - 1, paraSource, paraTransit, paraDestination);
printf("%c -> %c \r\n", paraSource, paraDestination);
hanoi(paraN - 1, paraTransit, paraDestination, paraSource);
}// of if
}// of hanoi
/**
* Test the hanoi function.
*/
void hanoiTest() {
printf("---- addToTest begins. ----\r\n");
printf("2 plates\r\n");
hanoi(2, 'A', 'B', 'C');
printf("3 plates\r\n");
hanoi(3, 'A', 'B', 'C');
printf("---- addToTest ends. ----\r\n");
}// of addToTest
/*
The entrance.
*/
void main() {
hanoiTest();
}// of main
运行结果
总结
起源
汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
汉诺塔问题是一个经典的递归问题,最初由法国数学家 Edouard Lucas 提出。问题描述如下:
有三根柱子,分别为 A、B、C,A 柱子上有 n 个盘子,盘子大小不一,大盘子在下,小盘子在上。现在需要将 A 柱子上的所有盘子移动到 C 柱子上,每次只能移动一个盘子,且大盘子不能放在小盘子上面。在移动过程中可以使用 B 柱子作为中转站。
心得
1.自顶向下,逐渐求精
在解决汉诺塔问题时可以从简到难的过程思考。这个问题可以分解为三个子问题,即将 n-1 个圆盘从第一个柱子移动到第二个柱子,将第 n 个圆盘从第一个柱子移动到第三个柱子,再将 n-1 个圆盘从第二个柱子移动到第三个柱子。这三个子问题可以分别递归解决,最终得到整个问题的解。
2.函数调用,递归,分治
在汉诺塔问题中,因为要解决n的问题,可以使用函数和递归减小代码量,用函数分解三个子问题,并递归调用 hanoi() 函数来解决这些子问题。
3.不跨层
在我们编写代码前的分析中,我们要做到不跨层,例如汉诺塔问题中当我们思考移动3个盘子的问题时,我们不要超前的思考4个盘子的问题。
4.形参与实参
在调用函数完成递归时,我们要注意形参与实参的问题,我们使用形参来表示函数的输入变量,而用实参来表示函数调用时的具体值。
5.有意义和规范的标识
在编写代码时,使用有意义和规范的标识可以方便我们的理解,日后对函数的维护和修改。
6.时间复杂度
汉诺塔问题中的时间复杂度为 O(2^n),其中 n 是圆盘的数量。这是一个指数级别的复杂度,因此当n的值越来越大时,汉诺塔问题将变得非常复杂。
7 递归栈
通过物理逻辑在纸上根据代码对栈的工作进行画图,能够更加直观的看出递归栈是如何工作的,便于对问题的分析和总结。
8.空间复杂度
汉诺塔问题的空间复杂度O(n),其中 n 是圆盘的数量。