#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.
*/
int main() {
hanoiTest();
}// Of main
感悟:
1.汉诺塔问题的基本操作为将n-1个盘子从A通过B移至C,再将第n个移到B,最后再将C柱上的n-1个盘子,通过A移到B。
而无论是A->C还是C->A,其本质的操作都一样,所改变的只是函数的变量名,故它们可用同一个函数来执行,需要注意的是,递归程序由于其不断自我调用的特点,极难在程序逻辑上理解,故一般不要求完全跟踪程序所执行的每一步操作。
2.如果非要解释,由于汉诺塔游戏的特性想移动第n个到B就首先得移动n-1,依次不断类推,可知第一步是移动第一个,如果盘子数为奇数,则第一步移动到B,若盘子数为偶数,则第一个盘子移动到C柱。因为,如果盘子为偶数,则经历偶数次B 和C变量位置的互换,最终还是原变量位置,故奇数盘时移至B。但由于递归的特性,这不需要讨论,直接在一层递归结束后从原点移至终点就行,然后又是新的一层递归。
3.递归思想:汉诺塔问题是一种典型的递归问题,通过将问题分解为规模更小的子问题来解决整个问题。在编写递归函数时,需要确定好递归的边界条件和递归的处理方式。
4.数据结构:在汉诺塔问题中,我们需要使用栈来存储每个盘子的状态。栈是一种后进先出(Last In First Out)的数据结构,与递归算法的思想非常契合。在汉诺塔问题中,我们需要将一个盘子从一个柱子移动到另一个柱子,为了保证移动的正确性,需要按照从上到下的顺序将盘子存储在栈中。这样,我们就可以通过不断出栈和入栈的方式完成汉诺塔的移动。
5.思维能力:汉诺塔问题需要我们进行抽象思维,将问题抽象为栈的操作过程,而不是盘子的具体位置。同时,需要注意到汉诺塔问题存在多种解法,我们需要在不同的情况下选择不同的策略。
6.解决问题要从简单到复杂。汉诺塔问题是一个很好的例子,从解决一个盘子的情况开始,逐渐增加盘子的数量,最终得到解决所有盘子的方法。
7.诺塔问题还可以扩展到更多的场景中,例如有多个塔和多个盘子,可以通过类比和抽象的方式来解决。此外,汉诺塔问题还具有优美的数学性质,例如汉诺塔问题的解法具有唯一性,这也反映了数学在计算机科学中的重要性。
这是对以上代码分析后产生的感悟。
8.在网上看到还有将汉诺塔问题和二进制联系起来的文章。
我们可以将0号圆盘的移动认为是二进制中的个位计数,1号圆盘认为是二进制中的十位计数,2号圆盘认为是二进制中的百位计数。即每动在个位上加一,就可以认为移动了一次0号盘,每在十位上加一就可以认为是移动了一次1号盘,每在百位上加一个一,就可以认为是移动了一次2号盘。而我上述所描述的过程就是 000 001 010 011 100 101 110 111。那么就是分别移动了对应的圆盘。