C语言函数递归调用汉诺塔问题
int main()
{
void hanoi(int n,char one ,char two,charthree);
int m;
printf("input the number of diskes:\n");
scanf("%d",&m);
printf("The step to move %ddiskes:\n",m);
hanoi(m,'A','B','C');
}
void hanoi(int n,char one ,char two,charthree)
{
void move(char x,char y);
if(n==1)
move(one,three);
else
{
hanoi(n-1,one,three,two);
move(one,three);
hanoi(n-1,two,one,three);
}
}
void move(char x,char y)
{
printf("%c->%c\n",x,y);
}
/////////////////////////////////////////////////////////////////////分割线///////////////////////////////////
我现在理解函数可能陷入一个误区了,就拿这题来说。hanoi函数内部没有一条语句是起作用的。什么意思,比如我假定一个新函数add:
Int add(int a,int b)
{
Int c;
c=a+b;
return c;
}
这个函数我通过c=a+b;这条语句很明显就知道了这是执行相加运算的函数。但是反观这道题,hanoi直接就是个空函数,里面一条起作用的语句都没有,怎么就能运算出结果,这点让我非常的头疼。而且在hanoi函数中又调用了hanoi函数,我知道这是递归。但是这函数里面是空的啊。
void hanoi(int n,char one ,char two,charthree);这只是单纯的定义函数变量,没有具体功能。只是说理解的时候可以理解成:将n个盘子从one通过two移动到three。但计算机不会这么理解。它是怎么通过hanoi空函数实现功能的,这点才是我最想,也是最迷糊的地方,希望你能帮我指点迷津 展开
我一步步的给你讲,就会懂啦:
首先hanoi函数如果把当中的move函数给去掉,就变成了:
void hanoi(int n, char one , char two, charthree)
{
if(n == 1)
printf("%c->%c\n", one, three);
else
{
hanoi(n - 1, one, three, two);
printf("%c->%c\n", one, three);
hanoi(n - 1, two, one, three);
}
}
也就是把move(one,three),变成了printf("%c->%c\n", one, three);。少了一个函数,更加清晰
所以这里的hanoi函数就有了执行的内容:printf
下面以3个盘子为例进行模拟计算机的执行过程:
1、hanoi(3,A,B,C),开始了这步,进入第一层函数,计算机在函数中会进行自我的再次调用(第7行代码)
2、(第7行):hanoi(2,A,C,B),于是这又是一个新的hanoi函数,这里我把它成为第二层函数
同样执行到第7行,卡住了,再次一次自我的调用
3、(进入第三层函数):hanoi(1,A,B,C),这里的第三层n=1,所以在第四行就显示出了"A->C",至此,第三层函数结束,回到调用他的第二层函数
4、在第二层当中,继续第8行的内容,所以显示出"A->B",继续运行,到第9行,开始了有一次自我调用
5、把她称为贰号第三层函数吧。。。hanoi(1,B,A,C),和第3步类似,这一层函数显示出了"B->C",然后结束函数,返回调用它的第二层函数
6、第二层函数执行完毕,返回调用它的第一层函数
7、第一层函数中执行到第8行,显示出"A->C",然后执行第9行:hanoi(2,B,A,C)
............
如果看到了这里理清楚了关系就会懂啦,接下来还有一半,如果都写下来就太复杂了-。-
你所说的空函数是指没有返回值,但是这里利用的是电脑调用函数的那种关系来解决的问题,比如上面的3步,会自动返回到第二层函数并继续
还可以这样理解汉诺塔,汉诺塔其实是将复杂的问题简单化,
先不管他有多少个盘子从A到C,我只把它视作3步
就像上面那样找个例子,反复的按照代码模拟计算机运行,过个五次六次,就会懂啦
这个程序是一个递归程序,并不是直接出结果的,我简单解释下好了
首先你要明白函数调用过程,比如:
……
fun();
a++;
……
在这个例子中,fun结束了会执行a++这种语句,这点没问题吧。递归函数会重复调用同名的函数,但是不代表退出了一个同名函数就直接退出了整个函数,而是一层层的返回的。
以你的程序为例:(同一个缩进表示同一层,每缩进一次就进入下一层调用)
//取n=3
hanoi(3,'A','B','C');//main中调用
hanoi(2,'A','C','B');//n=3,执行else
hanoi(1,'A','B','C');//n=2,执行else
move('A','C');//n=1,执行if,完毕后return到调用出执行下一句
move('A','B');//else中第二句
hanoi(1,'C','A','B');//else中第三句
move('C','B');//返回调用处,但hanoi(2,'A','C','B')也执行完毕,继续返回
move('A','C');
hanoi(2,'B','A','C');
hanoi(1,'B','C','A');
move('B','A');
move('B','C');
hanoi(1,'A','B','C');
move('A','C');
//返回至hanoi(1,'A','B','C');
//返回至hanoi(2,'B','A','C');
//返回至main中调用hanoi(3,'A','B','C');
递归虽然有点抽象,但还是按照函数调用的规则的,都是调用,结束返回到调用处。刚开始都是展开过程,直到遇到了递归结束条件,才结束递归调用的过程
你这里的递归函数并不是你说的空函数,你仔细看下在这个函数执行过程中,肯定有某些语句是起作用的,你这里就是move起作用了,你仔细理解下
#include<stdio.h>
void move(int n,char a,char b,char c)
{
if(n==1)
printf("\t%c->%c\n",a,c); //当n只有1个的时候直接从a移动到c
else
{
move(n-1,a,c,b); //第n-1个要从a通过c移动到b
printf("\t%c->%c\n",a,c);
move(n-1,b,a,c); //n-1个移动过来之后b变开始盘,b通过a移动到c,这边很难理解
}
}
main()
{
int n;
printf("请输入要移动的块数:");
scanf("%d",&n);
move(n,'a','b','c');
}
如果你输入的m为1,则直接调用move(one,three),然后直接输入 A-->C换行
如果你输入的m不为1,假设为2,则执行过程如下
执行一次hanoi(1,one,three,two),执行 move(one,three),然后直接输出A-->B换行
执行一次move(one,three),然后直接输出 A-->C换行
执行一次hanoi(1,two,one,three),执行move(one,three),然后直接输出B-->C换行
如果你输入的数字>2那就相应的进入到更多层的hanoi()函数中循环