在計算機語言中,漢諾塔是遞迴呼叫的經典例子,然而現有的程式基本上都是使用4個引數項進行遞迴呼叫,即塔層數和原在塔座、借助塔座、目標塔座。程式雖然簡潔,但感覺不夠清晰,以c語言為例,如定義函式為void hanoi(int n,char x,char y,char z),呼叫代入為:hanoi(m,a,b,c);,並將其中的第三個引數char y(b)解釋為借助 ,至於為什麼要借助、怎麼借助的,借助後又如何等等,是需要認真思考才能領悟。本人寫了這個去掉借助塔座引數,只用塔層數和原在塔座名、目標塔座名三個的引數c語言程式,為了能讓程式清楚把源**打在執行結果中,具體如下:
#include
int main()
\n",110,34,37,34);
printf("int hanoi(int n,char x,char z)\n;\n");
printf("if(x=='b';\n");
printf("if(x=='c';\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)
;if(x=='b');
if(x=='c');
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
int main()
int hanoi(int n,char x,char y,char z)
以上是本人對漢諾塔遞迴呼叫的理解及形成程式,希望能給學習遞迴呼叫提供些幫助。
漢諾塔程式
include stdio.h void move char x,char y 自定義move函式,用來將塊從起始柱子x移動到目標柱子y,這裡的x,y為形參,不代表具體哪根柱子 void hannuota int n,char a,char b,char c 自定義hannuota函式,這裡的a,b...
93 漢諾塔(三)
時間限制 3000 ms 記憶體限制 65535 kb 難度 3 描述 在印度,有這麼乙個古老的傳說 在世界中心貝拿勒斯 在印度北部 的聖廟裡,一塊黃銅板上插著三根寶石針。印度教的主神梵天在創造世界的時候,在其中一根針上從下到上地穿好了由大到小的64片金片,這就是所謂的漢諾塔。不論白天黑夜,總有乙個...
1863 漢諾塔(三)
時間限制 3 sec 記憶體限制 64 mb 提交 42 解決 29 您該題的狀態 已完成 提交 狀態 討論版 在印度,有這麼乙個古老的傳說 在世界中心貝拿勒斯 在印度北部 的聖廟裡,一塊黃銅板上插著三根寶石針。印度教的主神梵天在創造世界的時候,在其中一根針上從下到上地穿好了由大到小的64片金片,這...