#include <stdio.h>
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);
printf("paraSource:%p, paraDestination:%p, paraTransit:%p \r\n",¶Source,¶Destination,¶Transit);
hanoi(paraN - 1, paraTransit, paraDestination, paraSource);
}
}
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");
}
void main() {
hanoiTest();
}
结果
1:自顶向下,逐渐求精,函数调用:
从最顶上的盘子开始移动,然后移动下面的盘子,用函数来表示这个过程
2:递归与分治(基础与归纳):
如果只有一个盘子在A柱上,只需直接移至C柱即可,否则需做以下步骤:
1:用C柱做过渡,将A柱上的(n-1)个盘子移至B柱。
2:将A柱上的最后一个盘子移至直接移至C柱。
3:用A柱做过渡,将B柱上的(n-1)个盘子移至C柱上。
这样n个盘子变成了n-1个盘子的问题,依次这么进行下去,最终会变成一个盘子的问题。
3:不要跨层分析:
在分析的时候,我们头脑应该只有两个东西:A柱这一层待移动的盘子和下面所有未移动的盘子,如果将问题具体化去逐个分析下面的盘子,就会陷进去。
4:形参与实参:
在函数调用的过程中,系统会给传入的参数另外分配地址,形参所储存的东西与实参一样,但由于地址不同,改变形参并不能改变实参。
5:有意义,规范的标识符:
我们命名变量时候,不应该为了图方便而将变量名设置简单,这样其他人读不懂我们的代码,我们自己写了很多代码的时候也可能也会搞混变量的关系。
6:时间复杂度:
设盘子个数为n时,需要T(n)步,把A柱子(n-1)个盘子移到B柱子,需要T(n-1)步,A柱子最后一个盘子移到C柱子一步,B柱子上n-1个盘子移到C柱子上T(n-1)步。
得递推公式T(n)= 2 * T(n-1) + 1
所以汉诺塔问题的时间复杂度为O(2^n);
7:递归栈:
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100 //定义栈的最大大小
typedef struct
{
int top; //栈顶指针
int data[MAXSIZE]; //栈的数据
} Stack;
// 初始化栈
void init(Stack *s)
{
s->top = -1;
}
// 判断栈是否为空
int isEmpty(Stack *s)
{
return s->top == -1;
}
// 判断栈是否已满
int isFull(Stack *s)
{
return s->top == MAXSIZE - 1;
}
// 入栈操作
void push(Stack *s, int item)
{
if (isFull(s))
{
printf("栈已满\n");
return;
}
s->data[++s->top] = item;
}
// 出栈操作
int pop(Stack *s)
{
if (isEmpty(s))
{
printf("栈已空\n");
return -1;
}
return s->data[s->top--];
}
// 汉诺塔递归函数,n表示盘子数量,A、B、C分别表示三个柱子
void hanoi(int n, Stack *A, Stack *B, Stack *C)
{
if (n == 1)
{
push(C, pop(A)); // 将A柱子顶部的盘子移动到C柱子
}
else
{
hanoi(n - 1, A, C, B); // 将A柱子的前n-1个盘子通过C柱子移动到B柱子
push(C, pop(A)); // 将A柱子剩下的一个盘子移动到C柱子
hanoi(n - 1, B, A, C); // 将B柱子上的n-1个盘子通过A柱子移动到C柱子
}
}
int main()
{
int n=8; //盘子数量
Stack A, B, C; //定义三个栈分别表示三个柱子
init(&A);
init(&B);
init(&C);
for (int i = n; i >= 1; i--)
{
push(&A, i);
}
// 进行汉诺塔移动
hanoi(n, &A, &B, &C);
return 0;
}
8:空间复杂度:
通过用栈实现汉诺塔问题,很容易知道其复杂度为O(n)。
通过学习,我了解了递归的奇妙之处,并且学会了如何去分析递归的空间和时间复杂度