三参数的汉诺塔c程序

在计算机语言中,汉诺塔是递归调用的经典例子,然而现有的程序基本上都是使用4个参数项进行递归调用,即塔层数和原在塔座、借助塔座、目标塔座。程序虽然简洁,但感觉不够清晰,以c语言为例,如定义函数为void hanoi(int n,char x,char y,char z){…},调用代入为:hanoi(m,a,b,c);,并将其中的第三个参数char y(b)解释为借助 ,至于为什么要借助、怎么借助的,借助后又如何等等,是需要认真思考才能领悟。本人写了这个去掉借助塔座参数,只用塔层数和原在塔座名、目标塔座名三个的参数c语言程序,为了能让程序清楚把源代码打在执行结果中,具体如下:

#include<stdio.h>

int main()

{

int hanoi(int n,char x,char z);

int m;

char c;

printf("#include<stdio.h>\nint main()\n{\nint hanoi(int n,char x,char z);\nint m;\nchar c;\n");

printf("pri%ctf(%cinput the number of diskes:%c);\n",110,34,34);

printf("sca%cf(%c%cd%c,%cm);\n",110,34,37,34,38);

printf("pri%ctf(%cthe step to moveing %cd diskes:%c%c%c,m);\n",110,34,37,92,110,34);

printf("if(m==1)pri%ctf(%cA-->C%c);else hanoi(m,'A','C');\n",110,34,34);

printf("c=getchar();\npri%ctf(%c%cc%c,c=getchar());\nreturn 0;\n}\n",110,34,37,34);

printf("int hanoi(int n,char x,char z)\n{\nchar y;\n");

printf("if(x=='A'{ if(z=='B')y='C';else y='B';};\n");

printf("if(x=='B'{ if(z=='A')y='C';else y='A';};\n");

printf("if(x=='C'{ if(z=='B')y='A';else y='B';};\n");

printf("if(n-1==1)pri%ctf(%c%cc-->%cc%c%c%c,x,y);else hanoi(n-1,x,y);\n",110,34,37,37,92,110,34);

printf("pri%ctf(%c%cc-->%cc%c%c%c,x,z);\n",110,34,37,37,92,110,34);

printf("if(n-1==1)pri%ctf(%c%cc-->%cc%c%c%c,y,z);else hanoi(n-1,y,z);\n}\n\n",110,34,37,37,92,110,34);

printf("input the number of diskes:");

scanf("%d",&m);

printf("the step to moveing %d diskes:\n",m);

if(m==1)printf("A-->C");else hanoi(m,'A','C');

c=getchar();

printf("%c",getchar());

return 0;

}

int hanoi(int n,char x,char z)

{

char y;

if(x=='A'){ if(z=='B') y='C';else y='B';};

if(x=='B'){ if(z=='A') y='C';else y='A';};

if(x=='C'){ if(z=='B') y='A';else y='B';};

if(n-1==1)printf("%c-->%c\n",x,y);else hanoi(n-1,x,y);

printf("%c-->%c\n",x,z);

if(n-1==1)printf("%c-->%c\n",y,z);else hanoi(n-1,y,z);

}

说明:

1层的汉诺塔直接从原在塔座(以下或称为x)移到目标塔座(以下或称为z),而1层上面还有其他层的,利用hanoi函数分解为三个步骤:先把其他层从原在塔座移开到另一个塔座(以下称为过渡塔座或y),再把第1层从原在塔座移到目标塔座,最后把过渡塔座的其他层移合在目标塔座,即移开、移到、移合三步骤。其他层是一层,可以直接移开,每步骤都一步完成,其他层是多层,移开和移合都不能直接一步完成,需要进行再分解,而再分解还是按照移开、移到、移合的原则进行,即在函数中调用本身函数。例如:

其他层是一层的,即汉诺塔是2层,进入hanoi函数(x=A z=C),因为第2层上面没有其他层,可以直接移开,即第2层从x到y(A到B第一步),然后是第1层上面没有其他层,可以直接移开,从x到z(A到C第二步),最后是第2层从y到z(B到C第三步)。

其他层是二层,即汉诺塔是3层,先进入hanoi函数(x=A z=C),利用函数分解为:把第2、第3层移开从x到y(A到B),然后把第1层移到从x到z(A到C),最后把第2、第3层移合从y到z(B到C)三步骤。第2、第3层的移开和移合是不能一步完成,需要再分解,即把第2层上面的第3层从x移开到z,然后第2层从x移到y,最后第3层再从z移合到y,这样第2第3层都移开到了y。其移开分解的函数是hanoi(n-1,x,y)(递归调用),而移合分解的函数是hanoi(n-1,y,z)(递归调用),x=A,y=B,z=C,而n-1是去掉第1层,只对第2、第3层进行分解。hanoi的定义是int hanoi(int n,char x,char z),移开和移合的区别在于参数不同,移开是将A,B输送给char x,char z,分解得到x到y(A到C),x到z (A到B),y到z(B到C)三步骤;而移合是将B,C输送给char x,char z,分解得到x到y(B到A),x到z (B到C),y到z(A到C)三步骤。因为第3层上面没有其他层,不用再分解,可以直接移开,即第3层从A到C(第一步),然后是第2层从A到B(第二步),最后是第3层再从C到B(第三步),这样就完成了第2层和第3层从A到B的移开,这时,第1层上面没有了其他层,可直接从A到C(第四步),然后再把第2层和第3层从B移合到C。即第3层从B到A(第五步),第2层从B到C(第六步),第3层再从A到C(第七步),其中第3层移动4次,第2层移动2次,第1层移到1次。

假如,在开始移动时,发现第3层上面还有一个隐藏层,实际是四层,原来的第一步将第3层从A到C,不能直接移动,只能将隐藏层先移开从A到B(第一步),然后将第层3层从A到C(第二步),再将隐藏层移合从B到C(第三步)。因为多了隐藏层,原第3层的一步直接移动,变成三步组合移动。移动因第3层的4次移动,步数由7步增加到15步。

移开,移到,移合不但是下层和上层的分解规律,同时也是下层和上层及再上层的位置规律。如下层是由x到z,则上层必须先到y,下层才能到z,而上层要到y,其再上层必须先到z后,才能到y,若还有再再上层,则再再上层先到y。如果把原在塔座看为头,把要移到的塔座看为尾,就会发现头不变,尾交换,这是移开的规律,而移合的规律则是,尾不变,头交换。可逆向理解,如6层汉诺塔从x移到y,有1、2、3到63这些步,如果从63往回到1,就是从y到x的移动的步骤。在这个过程中,就会出现:下层先由z到x,然后上层y到x,再上层z到x,再再上层y到x。

另外,对于x、y、z这三个数值,y虽然是推算的,但也是固定存在的,如果把y也设定为参数,并在调用时改变一下位置,然后有选择的使用,不但能减去推算语句,也不影响交换使用。具体为:即在移开时,让x,z,y和x,y,z交替调用,只使用第一个和第三个参数,这样下层是x到y,上层就是x到z,再上层是x到y。同理,移合时让y,x,z和x,y,z交替调用,也使用第一个和第三个参数,这样下层是y到z,上层就是x到z,再上层是y到z。

#include<stdio.h>

int main()

{

int hanoi(int n,char x,char y,char z);

int m;

printf("input the number of diskes:");

scanf("%d",&m);

printf("the step to moveing %d diskes:\n",m);

if(m==1)printf("A-->C");

else hanoi(m,'A','B','C');

return 0;

}

int hanoi(int n,char x,char y,char z)

{

if(n-1==1)printf("%c-->%c\n",x,y);else hanoi(n-1,x,z,y);

printf("%c-->%c\n",x,z);

if(n-1==1)printf("%c-->%c\n",y,z);else hanoi(n-1,y,x,z);

}

以上是本人对汉诺塔递归调用的理解及形成程序,希望能给学习递归调用提供些帮助。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值