{
if (n == 0) return; //base case
TOH(n-1, start, temp, goal); //把n-1個圓盤從start柱移到temp柱,goal作爲此次的輔助柱
move(start,goal); //從start柱移動一塊圓盤到goal柱
TOH(n-1, temp, goal, start); //把temp柱中的n-1個圓盤移到goal柱
return;
}
#include <conio.h>
#include "StackInterface.h"//這個頭文件,可以在棧那篇文章中找到,也可以自己用標準庫中的stack改一下面的程序即可
using namespace std;
/*
現在我們來定義一個棧的元素類:TaskPaper任務紙
由下屬B、C對子任務的分解情況,很容易看出,
可以把任務分成兩類:
1、移動n-1個圓盤。這說明,這種任務可以繼續分解。
2、移動1個圓盤。這說明,這種任務無法再分,可以執行移動操作。
那麼,我們可以定義一個枚舉類型,這個枚舉類型作爲棧元素
的一個數據成員,用來指示到底是繼續分解,還是作出移動操作。
*/
enum Flag {toMove, toDecompose};//移動、繼續分解
enum Pole {start, goal, temp}; //柱的三種狀態,既然起始柱、目標柱、臨時柱(也叫輔助柱)
class TaskPaper //任務紙類,將作爲棧的元素類
{
public:
Flag flg; //任務分類
int num; //任務規模
Pole A, B, C; //三根柱
TaskPaper(int n, Pole a, Pole b, Pole c, Flag f)
{
flg = f;
num = n;
A = a;
B = b;
C = c;
}
};
void TOH(int n, Pole s, Pole t, Pole g)//用棧實現的漢諾塔函數
{
LStack<TaskPaper *> stk;
stk.push(new TaskPaper(n,s,t,g, toDecompose)); //上司A放第一張任務紙到辦公桌上
TaskPaper * paperPtr;
long step=0;
while (stk.pop(paperPtr)) //如果辦公桌上有任務紙,就拿最上面的一張來看看
{
if (paperPtr->flg == toMove || paperPtr->num == 1)
{
++step;
if (paperPtr->A == start && paperPtr->B == goal)
{
cout<<"第"<<step<<"步:從A柱移動一個圓盤到B柱。"<<endl;
}
else if (paperPtr->A == start && paperPtr->C == goal)
{
cout<<"第"<<step<<"步:從A柱移動一個圓盤到C柱。"<<endl;
}
else if (paperPtr->B == start && paperPtr->A == goal)
{
cout<<"第"<<step<<"步:從B柱移動一個圓盤到A柱。"<<endl;
}
else if (paperPtr->B == start && paperPtr->C == goal)
{
cout<<"第"<<step<<"步:從B柱移動一個圓盤到C柱。"<<endl;
}
else if (paperPtr->C == start && paperPtr->A == goal)
{
cout<<"第"<<step<<"步:從C柱移動一個圓盤到A柱。"<<endl;
}
else if (paperPtr->C == start && paperPtr->B == goal)
{
cout<<"第"<<step<<"步:從C柱移動一個圓盤到B柱。"<<endl;
}
}
else
{
int num = paperPtr->num;
Pole a = paperPtr->A;
Pole b = paperPtr->B;
Pole c = paperPtr->C;
if (a==start && c==goal)
{
//書中僅寫了這一種情況,而後面的五種的情況被作者大意地認爲是相同的,
//於是程序出錯了。我估計沒有幾個人發現這個問題,因爲只我這種疑心很重的人,
//纔會按照書中的思路寫一遍這種程序^_^
stk.push(new TaskPaper(num-1, b, a, c, toDecompose));//子任務執行順序爲3
stk.push(new TaskPaper(1,a,b,c,::toMove)); //子任務中執行順序爲2
stk.push(new TaskPaper(num-1, a, c, b, toDecompose));//子任務中執行順序爲1
}
else if (a==start && b==goal)
{
stk.push(new TaskPaper(num-1, c, b, a, toDecompose));//爲goal的柱狀態不變,其它兩根柱的狀態互換
stk.push(new TaskPaper(1,a,b,c,::toMove)); //移動操作中,柱的狀態不變
stk.push(new TaskPaper(num-1, a, c, b, toDecompose));//爲start的柱狀態不變,其它兩根柱的狀態互換
}
else if (b==start && a==goal)
{
stk.push(new TaskPaper(num-1, a, c, b, toDecompose));
stk.push(new TaskPaper(1,a,b,c,::toMove));
stk.push(new TaskPaper(num-1, c, b, a, toDecompose));
}
else if (b==start && c==goal)
{
stk.push(new TaskPaper(num-1, b, a, c, toDecompose));
stk.push(new TaskPaper(1,a,b,c,::toMove));
stk.push(new TaskPaper(num-1, c, b, a, toDecompose));
}
else if (c==start && a==goal)
{
stk.push(new TaskPaper(num-1, a, c, b, toDecompose));
stk.push(new TaskPaper(1,a,b,c,::toMove));
stk.push(new TaskPaper(num-1, b, a, c, toDecompose));
}
else if (c==start && b==goal)
{
stk.push(new TaskPaper(num-1, c, b, a, toDecompose));
stk.push(new TaskPaper(1,a,b,c,::toMove));
stk.push(new TaskPaper(num-1, b, a, c, toDecompose));
}
}
delete paperPtr;
}
}
void main()
{
TOH(3,start,temp,goal);
getch();
}
1、進棧初始化:把一張TaskPaper放到辦公桌面上。
2、出棧,即從辦公桌上取一張TaskPaper,如辦公桌上沒有任務紙(出棧失敗),則到第4步。
3、取出任務紙後,根據任務的信息,分兩種情況進行處理:
A、如果任務不可再分,則執行這個任務(在上面這個程序中,體現爲把搬運動作打印出來),返回到第2步。
B、否則,劃分成若干個子任務,並把這些子任務,按照執行任務的相反順序放進棧中,保證棧頂的任務永遠是下一次出棧時最應優先處理的,返回到第2步。
4、其它處理。