郁闷ing!想了一整天也没有结果的汉诺塔问题..

pestpatrol 2006-04-27 08:05:12
算法我已经弄的很明白了...标注在源程序中
可就是看不懂源程序(函数的递归调用)
这段程序到底怎么走的哩?
我是这么想的~
程序首先从main()开始执行起
输入n变量的值为3
调用movedisk()函数 传入盘子数 n 以及A,B,C(三个针的代表符号)三个变量实参数
分别传给了movedisk()函数中的n A B C四个形参
步骤如下:
n=3; n>1所以调用自己 movedisk(n-1,A,C,B);[形式参数中的值依次变为了2 A C B]
n=2; n>1所以再一次调用自己 movedisk(n-1,A,C,B); [形式参数中的值依次变为了1 A B C]
n==1 所以执行

else
printf("Move disk 1 from post %c to post %c.\n",A,C);
即输出结果为 Move disk 1 from post A to post C
然后程序还怎么走里?偶觉得程序就结束拉。。。

#include<stdio.h>
movedisk(int n,char A,char B,char C)
{
if(n>1){
movedisk(n-1,A,C,B);/*1.将n-1个盘从A通过C移动到B*/
printf("Move disk %d from post %c to post %c.\n",n,A,C);
movedisk(n-1,B,A,C);/*3.再将n-1个盘从B通过A移动到C*/
}
else
printf("Move disk 1 from post %c to post %c.\n",A,C);
/*2.n==1 将A上的一个盘移动到C*/
}
main()
{
int n;
char A='A',B='B',C='C';
printf("Please input a digit of disk first:\n");
scanf("%d",&n);
movedisk(n,A,B,C);
}

...全文
418 15 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
zcjblueice 2006-05-06
  • 打赏
  • 举报
回复
我觉得不要解释的那么复杂,刚开始我也不明白,如果有几十个盘子要顺着正常的思路一个个的去想,那爱因斯坦估计能想通了,其实定义写的最简单了,子程序或子函数反复的调用自己,并传入不同的变量来执行的程序设计技巧。一般来讲,里面传递的参数一般都是递增或递减的,但是要注意有个递归结束条件。找个递归阶乘看看就好了,但是我想你的问题是看不懂汉诺塔问题的源代码,这中间和一般的递归一次到就n-1不同,涉及到两次搬动,才能转到hano(from,to,auxiliary,n-1)上,先是目的和辅助交换,然后来源和辅助交换,我看数据结构的时候一开始也看不明白这个地方,呵呵,我也可以发个帖子帮助别人了。
zhangwanlong 2006-05-06
  • 打赏
  • 举报
回复
高中课改的数学的练习册有这道题
caiyujie87 2006-05-06
  • 打赏
  • 举报
回复
up
zhiguo_he 2006-05-04
  • 打赏
  • 举报
回复
要把递归的部分看成整体,想多了会晕的
chenhu_doc 2006-05-04
  • 打赏
  • 举报
回复
以上贴的是 Hanoi塔问题 的解析
chenhu_doc 2006-05-04
  • 打赏
  • 举报
回复
Hanoi塔问题是一个典型的可用递归方法解决的问题(递归问题通常可转化为非递归问题)[2]。算法分析如下,设A上有n个盘子。
如果n=1,则将圆盘从A直接移动到C。
如果n=2,则:
(1)将A上的n-1(等于1)个圆盘移到B上;
(2)再将A上的一个圆盘移到C上;
(3)最后将B上的n-1(等于1)个圆盘移到C上。
如果n=3,则:
A)将A上的n-1(等于2,令其为n`)个圆盘移到B(借助于C),步骤如下:
(1)将A上的n`-1(等于1)个圆盘移到C上。
(2)将A上的一个圆盘移到B。
(3)将C上的n`-1(等于1)个圆盘移到B。
B)将A上的一个圆盘移到C。
C)将B上的n-1(等于2,令其为n`)个圆盘移到C(借助A),步骤如下:
(1)将B上的n`-1(等于1)个圆盘移到A。
(2)将B上的一个盘子移到C。
(3)将A上的n`-1(等于1)个圆盘移到C。到此,完成了三个圆盘的移动过程。

从上面分析可以看出,当n大于等于2时, 移动的过程可分解为三个步骤:第一步 把A上的n-1个圆盘移到B上;第二步 把A上的一个圆盘移到C上;第三步 把B上的n-1个圆盘移到C上;其中第一步和第三步是类同的。 当n=3时,第一步和第三步又分解为类同的三步,即把n`-1个圆盘从一个针移到另一个针上,这里的n`=n-1。


Hanoi塔问题中函数调用时系统所做工作

一个函数在运行期调用另一个函数时,在运行被调用函数之前,系统先完成3件事:

①将所有的实参、返回地址等信息传递给被调用函数保存。

②为被调用函数的局部变量分配存储区;

③将控制转移到被调用函数的入口。

从被调用函数返回调用函数前,系统也应完成3件事:

①保存被调用函数的结果;

②释放被调用函数的数据区;

③依照被调用函数保存的返回地址将控制转移到调用函数。

当有多个函数构成嵌套调用时,按照“后调用先返回”的原则(LIFO),上述函数之间的信息传递和控制转移必须通过“栈”来实现,即系统将整个程序运行时所需的数据空间安排在一个栈中,每当调用一个函数时,就为其在栈顶分配一个存储区,每当从一个函数退出时,就释放其存储区,因此当前运行函数的数据区必在栈顶。堆栈特点:LIFO,除非转移或中断,堆栈内容的存或取表现出线性表列的性质。正是如此,程序不要求跟踪当前进入堆栈的真实单元,而只要用一个具有自动递增或自动递减功能的堆栈计数器,便可正确指出最后一次信息在堆栈中存放的地址。

一个递归函数的运行过程类型于多个函数的嵌套调用,只是调用函数和被调用函数是同一个函数。因此,和每次调用相关的一个重要的概念是递归函数运行的“层次”。假设调用该递归函数的主函数为第0层,则从主函数调用递归函数为进入第1层;从第i层递归调用本函数为进入下一层,即i+1层。反之,退出第i层递归应返回至上一层,即i-1层。为了保证递归函数正确执行,系统需设立一个“递归工作栈”,作为整个递归函数运行期间使用的数据存储区。每一层递归所需信息构成一个“工作记录”,其中包括所有实参、所有局部变量以及上一层的返回地址。每进入一层递归,就产生一个新的工作记录压入栈顶。每退出一层递归,就从栈顶弹出一个工作记录,则当前执行层的工作记录必是递归工作栈栈顶的工作记录,称这个记录为“活动记录”,并称指示活动记录的栈顶指针为“当前环境指针”。
stonepeter 2006-04-28
  • 打赏
  • 举报
回复
要真正理解Hanio塔的问题是有个过程的。我给几个建议:
1、再去看看其他递归程序,比如说计算数字的递归函数(生小兔子问题,弗不拉奇数列问题,类比一下;
2、去看看关于STACK的内容,去深入体会一下;
3、动手画一下数值比较小的时候的移动情况,如果再有不明白,多画几次,包括画数值比较大的。
4、多花点时间,相信很快就可以明白了。
祝你好运!
yuanchuang 2006-04-28
  • 打赏
  • 举报
回复
楼上的说得很“玄乎”,但就是正解。
----------------
这两天一直在听张震鬼故事……
cihw2005 2006-04-28
  • 打赏
  • 举报
回复
楼上的说得很“玄乎”,但就是正解。
feny911 2006-04-28
  • 打赏
  • 举报
回复
楼上废话,也是正解。
递归和数学归纳法的发明有力地证明了天才和疯子的确只有一纸之隔。

言归正传,学递归别想太多,这东西越想多越想不明白。
回忆一下学过的数学归纳法,很相似的。(或者说刚好相反)
chinesegxf 2006-04-27
  • 打赏
  • 举报
回复
刚学都是不好理解的,过一年就理解了
sankt 2006-04-27
  • 打赏
  • 举报
回复
汗,怎么中文都是乱码...
sankt 2006-04-27
  • 打赏
  • 举报
回复
#include<stdio.h>
#include<stdlib.h>

void movedisk(int n,char A,char B,char C)
{
if(n>1)
{
movedisk(n-1,A,C,B);/*1.½«n-1¸öÅÌ´ÓAͨ¹ýCÒÆ¶¯µ½B*/
printf("Move disk %d from post %c to post %c.\n",n,A,C);
movedisk(n-1,B,A,C);/*3.ÔÙ½«n-1¸öÅÌ´ÓBͨ¹ýAÒÆ¶¯µ½C*/
}
else
printf("Move disk 1 from post %c to post %c.\n",A,C);
/*2.n==1 ½«AÉϵÄÒ»¸öÅÌÒÆ¶¯µ½C*/
}
int main()
{
int n;
char A='A',B='B',C='C';
printf("Please input a digit of disk first:\n");
scanf("%d",&n);
movedisk(n,A,B,C);

system("pause");
return 0;

}

程序没有错,可能是你输入的n太大了
我这里运行良好.


汉诺塔是个指数时间复杂度算法.

pestpatrol 2006-04-27
  • 打赏
  • 举报
回复
肯定有错!大家帮我找找我的思路哪里出了问题
1. C 语言中的指针和内存泄漏 5 2. C语言难点分析整理 10 3. C语言难点 18 4. C/C++实现冒泡排序算法 32 5. C++中指针和引用的区别 35 6. const char*, char const*, char*const的区别 36 7. C中可变参数函数实现 38 8. C程序内存中组成部分 41 9. C编程拾粹 42 10. C语言中实现数组的动态增长 44 11. C语言中的位运算 46 12. 浮点数的存储格式: 50 13. 位域 58 14. C语言函数二维数组传递方法 64 15. C语言复杂表达式的执行步骤 66 16. C语言字符串函数大全 68 17. C语言宏定义技巧 89 18. C语言实现动态数组 100 19. C语言笔试-运算符和表达式 104 20. C语言编程准则之稳定篇 107 21. C语言编程常见问题分析 108 22. C语言编程易犯毛病集合 112 23. C语言缺陷与陷阱(笔记) 119 24. C语言防止缓冲区溢出方法 126 25. C语言高效编程秘籍 128 26. C运算符优先级口诀 133 27. do/while(0)的妙用 134 28. exit()和return()的区别 140 29. exit子程序终止函数与return的差别 141 30. extern与static存储空间矛盾 145 31. PC-Lint与C\C++代码质量 147 32. spirntf函数使用大全 158 33. 二叉树的数据结构 167 34. 位运算应用口诀和实例 170 35. 内存对齐与ANSI C中struct内存布局 173 36. 冒泡和选择排序实现 180 37. 函数指针数组与返回数组指针的函数 186 38. 右左法则- 复杂指针解析 189 39. 回车和换行的区别 192 40. 堆和堆栈的区别 194 41. 堆和堆栈的区别 198 42. 如何写出专业的C头文件 202 43. 打造最快的Hash表 207 44. 指针与数组学习笔记 222 45. 数组不是指针 224 46. 标准C中字符串分割的方法 228 47. 汉诺塔源码 231 48. 洗牌算法 234 49. 深入理解C语言指针的奥秘 236 50. 游戏外挂的编写原理 254 51. 程序实例分析-为什么会陷入死循环 258 52. 空指针究竟指向了内存的哪个地方 260 53. 算术表达式的计算 265 54. 结构体对齐的具体含义 269 55. 连连看AI算法 274 56. 连连看寻路算法的思路 283 57. 重新认识:指向函数的指针 288 58. 链表的源码 291 59. 高质量的子程序 295 60. 高级C语言程序员测试必过的十六道最佳题目+答案详解 297 61. C语言常见错误 320 62. 超强的指针学习笔记 325 63. 程序员之路──关于代码风格 343 64. 指针、结构体、联合体的安全规范 346 65. C指针讲解 352 66. 关于指向指针的指针 368 67. C/C++ 误区一:void main() 373 68. C/C++ 误区二:fflush(stdin) 376 69. C/C++ 误区三:强制转换 malloc() 的返回值 380 70. C/C++ 误区四:char c = getchar(); 381 71. C/C++ 误区五:检查 new 的返回值 383 72. C 是 C++ 的子集吗? 384 73. C和C++的区别是什么? 387 74. 无条件循环 388 75. 产生随机数的方法 389 76. 顺序表及其操作 390 77. 单链表的实现及其操作 391 78. 双向链表 395 79. 程序员数据结构笔记 399 80. Hashtable和HashMap的区别 408 81. hash 表学习笔记 410 82. C程序设计常用算法源代码 412 83. C语言有头结点链表的经典实现 419 84. C语言惠通面试题 428 85. C语言常用宏定义 450

70,020

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧