十年網(wǎng)站開(kāi)發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶(hù) + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營(yíng)維護(hù)+專(zhuān)業(yè)推廣+無(wú)憂(yōu)售后,網(wǎng)站問(wèn)題一站解決
#include#define MAXSTACK 10 /* 棧的最大深度 */int c = 1; /* 一個(gè)全局變量,表示目前移動(dòng)的步數(shù) */struct hanoi { /* 存儲(chǔ)漢諾塔的結(jié)構(gòu),包括盤(pán)的數(shù)目和三個(gè)盤(pán)的名稱(chēng) */

創(chuàng)新互聯(lián)專(zhuān)注于企業(yè)成都營(yíng)銷(xiāo)網(wǎng)站建設(shè)、網(wǎng)站重做改版、羅源網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5技術(shù)、商城開(kāi)發(fā)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站制作、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性?xún)r(jià)比高,為羅源等各大城市提供網(wǎng)站開(kāi)發(fā)制作服務(wù)。
int n;
char x, y, z;
};void move(char x, int n, char y) /* 移動(dòng)函數(shù),表示把某個(gè)盤(pán)從某根針移動(dòng)到另一根針 */
{
printf("%d. Move disk %d from %c to %cn", c++, n, x, y);
}void hanoi(int n, char x, char y, char z) /* 漢諾塔的遞歸算法 */
{
if (1 == n)
move(x, 1, z);
else {
hanoi(n - 1, x, z, y);
move(x, n, z);
hanoi(n - 1, y, x, z);
}
}void push(struct hanoi *p, int top, char x, char y, char z,int n)
{
p[top+1].n = n - 1;
p[top+1].x = x;
p[top+1].y = y;
p[top+1].z = z;
}void unreverse_hanoi(struct hanoi *p) /* 漢諾塔的非遞歸算法 */
{
int top = 0;while (top = 0) {
while (p[top].n 1) { /* 向左走到盡頭 */
push(p, top, p[top].x, p[top].z, p[top].y, p[top].n);
top++;
}
if (p[top].n == 1) { /* 葉子結(jié)點(diǎn) */
move(p[top].x, 1, p[top].z);
top--;
}
if (top = 0) { /* 向右走一步 */
move(p[top].x, p[top].n, p[top].z);
top--;
push(p, top, p[top+1].y, p[top+1].x, p[top+1].z, p[top+1].n);
top++;
}
}
}int main(void)
{
int i;
printf("reverse program:n");
hanoi(3, 'x', 'y', 'z');
printf("unreverse program:n");
struct hanoi p[MAXSTACK];
c = 1;
p[0].n = 3;
p[0].x = 'x', p[0].y = 'y', p[0].z = 'z';
unreverse_hanoi(p);return 0;
}
我以前收藏了一個(gè)別人的回答,你看看吧:
遞歸算法的出發(fā)點(diǎn)不是由初始條件出發(fā),而是把出發(fā)點(diǎn)放在求解的目標(biāo)上,從所求的未知項(xiàng)出發(fā)逐次調(diào)用本身的求解過(guò)程,直到遞歸的邊界(即初始條件)。
漢諾塔問(wèn)題的重點(diǎn)是分析移動(dòng)的規(guī)則,找到規(guī)律和邊界條件。
若需要將n個(gè)盤(pán)子從A移動(dòng)到C就需要(1)將n-1個(gè)盤(pán)子從A移動(dòng)到B;(2)將你第n個(gè)從A移動(dòng)到C;(3)將n-1個(gè)盤(pán)子再?gòu)腂移動(dòng)到C,這樣就可以完成了。如果n!=1,則需要遞歸調(diào)用函數(shù),將A上的其他盤(pán)子按照以上的三步繼續(xù)移動(dòng),直到達(dá)到邊界條件n=1為止。
思路清楚了,程序就好理解了。程序中的關(guān)鍵是分析好每次調(diào)用移動(dòng)函數(shù)時(shí)具體的參數(shù)和對(duì)應(yīng)的A、B、C塔的對(duì)應(yīng)的關(guān)系。下面來(lái)以實(shí)際的例子對(duì)照程序進(jìn)行說(shuō)明。
①move(int n,int x,int y,int z)
②{
③ if (n==1)
④ printf("%c--%c\n",x,z);
⑤ else
⑥ {
⑦ move(n-1,x,z,y);
⑧ printf("%c--%c\n",x,z);
⑨ {getchar();}//此句有必要用嗎?感覺(jué)可以去掉的吧
⑩ move(n-1,y,x,z);
}
}
比如有4個(gè)盤(pán)子,現(xiàn)在全部放在A塔上。盤(pán)子根據(jù)編號(hào)為1、2、3、4依次半徑曾大?,F(xiàn)在要將4個(gè)盤(pán)子移動(dòng)到C上,并且是按原順序羅列。首先我們考慮如何才可以將4號(hào)移動(dòng)到C呢?就要以B為中介,首先將上面的三個(gè)移動(dòng)到B。此步的操作也就是程序中的①開(kāi)始調(diào)入move函數(shù)(首次調(diào)用記為一),當(dāng)然現(xiàn)在的n=4,然后判斷即③n!=1所以不執(zhí)行④而是到⑤再次調(diào)用move函數(shù)(記為二)考慮如何將3個(gè)盤(pán)移動(dòng)到B的方法。此處是遞歸的調(diào)用所以又一次回到①開(kāi)始調(diào)入move函數(shù),不過(guò)對(duì)應(yīng)的參數(shù)發(fā)生了變化,因?yàn)檫@次要考慮的不是從A移動(dòng)4個(gè)盤(pán)到C,而是要考慮從A如何移動(dòng)移動(dòng)3個(gè)盤(pán)到B。因?yàn)閚=3,故不可以直接移動(dòng)要借助C做中介,先考慮將兩個(gè)移動(dòng)到C的方法,故再一次到⑤再一次遞歸調(diào)用move函數(shù)(記為三)。同理兩個(gè)盤(pán)還是不可以直接從A移動(dòng)到C所以要以B為中介考慮將1個(gè)移動(dòng)到B的過(guò)程。這次是以B為中介,移動(dòng)到C為目的的。接下來(lái)再一次遞歸調(diào)用move函數(shù)(記為四),就是移動(dòng)到B一個(gè),可以直接進(jìn)行。程序執(zhí)行③ ④句,程序跳出最內(nèi)一次的調(diào)用(即跳出第四次的調(diào)用)返回上一次(第三次),并且從第三次的調(diào)用move函數(shù)處繼續(xù)向下進(jìn)行即⑧,即將2號(hào)移動(dòng)到了C,然后繼續(xù)向下進(jìn)行到
⑩,再將已經(jīng)移到B上的哪一個(gè)移回C,這樣返回第二次遞歸(以C為中介將3個(gè)盤(pán)移動(dòng)到B的那次)。執(zhí)行⑧,將第三個(gè)盤(pán)從A移動(dòng)到B,然后進(jìn)入⑩,這次的調(diào)用時(shí)因?yàn)槭菍上的兩個(gè)盤(pán)移到B以A為中介,所以還要再一次的遞歸調(diào)用,對(duì)應(yīng)的參數(shù)傳遞要分析清楚,誰(shuí)是原塔誰(shuí)是目標(biāo)塔,誰(shuí)是中介塔。過(guò)程類(lèi)似于上面的分析,這里不再重復(fù)論述了。
將以下內(nèi)容全部復(fù)制到新建的源文件中:(本人自己寫(xiě)的,因?yàn)槟隳钦n本上的代碼,沒(méi)解釋?zhuān)瑫?shū)寫(xiě)不規(guī)范,很難理解清楚,所以我直接新寫(xiě)了一個(gè)完整的代碼,附帶詳細(xì)說(shuō)明)
#include stdio.h
//漢諾塔x層塔從A塔整體搬到C塔,中間臨時(shí)B塔。
//x層塔是從大到小往上疊放。每次移動(dòng)只能移動(dòng)一層塔。并且在移動(dòng)過(guò)程中必須保證小層在上邊
//借助B塔可以將x層塔全部從A搬到C上,并且符合要求(在移動(dòng)過(guò)程中大的那塊在下邊,小的那塊在上邊)
int main()
{
void tower(int x,char a,char b,char c); //聲明函數(shù)
int x=5,a='A',b='B',c='C'; //x表示有5層塔,具體要多少層自己修改這個(gè)值。abc分別表示ABC塔。
tower(x,a,b,c); //x層塔從a移動(dòng)到c的全過(guò)程,主程序只有這條有效語(yǔ)句
return 0;
}
//以下是tower函數(shù)的定義
//參數(shù)解析:x層塔放在a上,b是中間塔,c是目標(biāo)塔。即x層塔要從a搬到c上。
//此函數(shù)實(shí)現(xiàn)x層塔從a整體轉(zhuǎn)移到c上。以及這個(gè)過(guò)程是怎么搬的全部過(guò)程。
void tower(int x,char a,char b,char c)
{
if(x==1)printf("將%d從%c放到%c\n",x,a,c); //只有1層塔時(shí),直接從a搬到c上。
else //不止1層塔,則先將x-1層塔從a按照規(guī)律搬到b上,再將最后一塊從a搬到c上,最后再將b上的x-1層塔按照規(guī)律搬到c上。
{
tower(x-1,a,c,b); //先將x-1層塔從a按照規(guī)律搬到b上,注意參數(shù)b放在最后,因?yàn)榉旁谧詈蟮膮?shù)是準(zhǔn)備搬過(guò)去的目標(biāo)塔。
printf("將%d從%c放到%c\n",x,a,c); //將最后一塊從a搬到c上
tower(x-1,b,a,c); //最后再將b上的x-1層塔按照規(guī)律搬到c上,注意參數(shù)b放在開(kāi)頭,因?yàn)閤-1層是要從b上搬過(guò)去的。
}
}
*問(wèn)題分析與算法設(shè)計(jì)
這是一個(gè)著名的問(wèn)題,幾乎所有的教材上都有這個(gè)問(wèn)題。由于條件是一次只能移動(dòng)一個(gè)盤(pán),且不允許大盤(pán)放在小盤(pán)上面,所以64個(gè)盤(pán)的移動(dòng)次數(shù)是:
18,446,744,073,709,551,615
這是一個(gè)天文數(shù)字,若每一微秒可能計(jì)算(并不輸出)一次移動(dòng),那么也需要幾乎一百萬(wàn)年。我們僅能找出問(wèn)題的解決方法并解決較小N值時(shí)的漢諾塔,但很難用計(jì)算機(jī)解決64層的漢諾塔。
分析問(wèn)題,找出移動(dòng)盤(pán)子的正確算法。
首先考慮a桿下面的盤(pán)子而非桿上最上面的盤(pán)子,于是任務(wù)變成了:
*將上面的63個(gè)盤(pán)子移到b桿上;
*將a桿上剩下的盤(pán)子移到c桿上;
*將b桿上的全部盤(pán)子移到c桿上。
將這個(gè)過(guò)程繼續(xù)下去,就是要先完成移動(dòng)63個(gè)盤(pán)子、62個(gè)盤(pán)子、61個(gè)盤(pán)子....的工作。
為了更清楚地描述算法,可以定義一個(gè)函數(shù)movedisc(n,a,b,c)。該函數(shù)的功能是:將N個(gè)盤(pán)子從A桿上借助C桿移動(dòng)到B桿上。這樣移動(dòng)N個(gè)盤(pán)子的工作就可以按照以下過(guò)程進(jìn)行:
1) movedisc(n-1,a,c,b);
2) 將一個(gè)盤(pán)子從a移動(dòng)到b上;
3) movedisc(n-1,c,b,a);
重復(fù)以上過(guò)程,直到將全部的盤(pán)子移動(dòng)到位時(shí)為止。
*程序與程序注釋
#includestdio.h
void movedisc(unsigned n,char fromneedle,char toneedle,char usingneedle);
int i=0;
void main()
{
unsigned n;
printf("please enter the number of disc:");
scanf("%d",n); /*輸入N值*/
printf("\tneedle:\ta\t b\t c\n");
movedisc(n,'a','c','b'); /*從A上借助B將N個(gè)盤(pán)子移動(dòng)到C上*/
printf("\t Total: %d\n",i);
}
void movedisc(unsigned n,char fromneedle,char toneedle,char usingneedle)
{
if(n0)
{
movedisc(n-1,fromneedle,usingneedle,toneedle);
/*從fromneedle上借助toneedle將N-1個(gè)盤(pán)子移動(dòng)到usingneedle上*/
++i;
switch(fromneedle) /*將fromneedle 上的一個(gè)盤(pán)子移到toneedle上*/
{
case 'a': switch(toneedle)
{
case 'b': printf("\t[%d]:\t%2d.........%2d\n",i,n,n);
break;
case 'c': printf("\t[%d]:\t%2d...............%2d\n",i,n,n);
break;
}
break;
case 'b': switch(toneedle)
{
case 'a': printf("\t[%d]:\t%2d...............%2d\n",i,n,n);
break;
case 'c': printf("\t[%d]:\t %2d........%2d\n",i,n,n);
break;
}
break;
case 'c': switch(toneedle)
{
case 'a': printf("\t[%d]:\t%2d............%2d\n",i,n,n);
break;
case 'b': printf("\t[%d]:\t%2d........%2d\n",i,n,n);
break;
}
break;
}
movedisc(n-1,usingneedle,toneedle,fromneedle);
/*從usingneedle上借助fromneedle將N-1個(gè)盤(pán)子移動(dòng)到toneedle上*/
}
}
#includestdio.h
void move(char a,char b)
{
printf("%c-%c\n",a,b);
}
void f(int n,char a,char b,char c)
{
if(n==1) move(a,c);
else
{
f(n-1,a,c,b);
move(a,c);
f(n-1,b,a,c);
}
}
void main()
{
int n;
scanf("%d",n);
f(n,'a','b','c');
}
這是我的代碼 前面的是定義一個(gè)函數(shù) 這里遞歸體現(xiàn)在函數(shù)里面還有函數(shù) 于是會(huì)一次又一次的計(jì)算 直到最后把N-1以前的都移到B,最下面的移到C,再把其他的從B移到C。。 無(wú)返回的話(huà) 應(yīng)該是這里用void 沒(méi)有return返回?cái)?shù)值