汉诺塔代码:
#include<stdio.h>
void hanoi(int paraN, char paraSource, char paraDestination, char paraTransit) {
if(paraN <= 0) {
return 0;
} else {
hanoi(paraN - 1, paraSource, paraTransit, paraDestination);
printf("%c -> %c\r\n", paraSource, paraDestination);
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();
}
运行结果
![hanoi](https://i-blog.csdnimg.cn/blog_migrate/e315d390cb3a1f04ee79ea3d1ebfbe4c.png)
代码分析:
2 plates
- 首先将2传入,因为2!=0,进入第一个盘子的函数分析
- 第一个盘子函数中,首先进入0个盘子分析,直接返回,按顺序执行下一列代码,输出A->C,然后进入第二个0,直接返回
- 执行下一列代码,A->B
- 进入第二个盘子函数中,首先进入0个盘子分析,直接返回,按顺序执行下一列代码,输出C->B,然后进入第二个0,直接返回
- 程序运行完成
思维图
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/13ec6e1bb628d0a2d5e5dfdf497424b8.png)
3plates
- 首先将3传入,进入2plates,然后就和上面的分析步骤一样
思维图
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/644c972388c144a42cc526402f80fdfe.png)
心得体会
- 自顶向下,逐渐求精:Hanoi问题不要看的太复杂,在移动的时候一层一层的往下分解,不要跨层分析,会把问题变得很复杂,就从上而下逐层分析就好了
- 函数调用、递归与分治:在解决Hanoi问题时,主要使用到递归,将它打包到一个函数里面调用,详细做法已经在上面讲过了,这里不再赘述
- 形参与实参:实参是主调函数中的,形参是被调函数中的,例如Hanoi问题中,相对于(2,‘A’,‘B’,‘C’)而言,paraSource,paraTransit,paraDestination就是形参
- 有意义、规范的标识符:像paraSource,paraTransit,paraDestination这种表达明确的命名就是有意义、有规范的标识符,这种表意明确的标识符有利于对代码的解读和理解。命名要规范,不要为了节省时间简化命名,会导致问题更加难懂
- 时间复杂度:Hanoi问题的时间复杂度为O(2^n), 我们假设Hanoi的执行时间是T(n),第一句的执行时间是O(1);else中递归调用的执行时间是T(n-1),赋值执行时间为O(1),所以执行时间是O(1) + T(n-1)。计算出时间复杂度为O(2^n)
- 递归栈:Hanoi问题是通过将一个一个盘子压入栈然后从小到大解决一个出一次栈,详情如思维图所示,代码的思维图从左往右读取
- 空间复杂度:递归是函数自己调用自己,由于函数每次执行都是在内存中开辟新的空间,所以每次函数调用都不会丢失或者覆盖原来函数的值,所以其空间复杂度为O(n)