當前位置:編程學習大全網 - 編程語言 - 漢諾塔匯編程序設計報告

漢諾塔匯編程序設計報告

STL學習筆記:用非遞歸的方法實現漢諾塔問題

STL學習筆記:用非遞歸的方法實現漢諾塔問題

shaohui_1983#163.com t,srctop,dsttop,britop,last = 0;

7 stack<int> ssrc,sdst,sbri;

8 for (cnt=1 ;cnt<=scale; cnt++)

9 ssrc.push(cnt);

10

11 while (sdst.size() != scale)

12 {

13 srctop = ssrc.empty() ? 0 : ssrc.top();

14 dsttop = sdst.empty() ? 0 : sdst.top();

15 britop = sbri.empty() ? 0 : sbri.top();

16

17 if (last != srctop && ((srctop%2 && srctop>dsttop) || ((srctop%2==0) && srctop>britop)))

18 {

19 ssrc.pop();

20 last = srctop;

21 srctop % 2 ? sdst.push(srctop) : sbri.push(srctop);

22 if (srctop % 2)

23 cout<<"move disk "<<scale-srctop+1<<" from \'a\' to \'c\'\n";

24 else

25 cout<<"move disk "<<scale-srctop+1<<" from \'a\' to \'b\'\n";

26 }

27

28 if (last != britop && ((britop%2 && britop>srctop) || ((britop%2==0) && britop>dsttop)))

29 {

30 sbri.pop();

31 last = britop;

32 britop % 2 ? ssrc.push(britop) : sdst.push(britop);

33

34 if (britop % 2)

35 cout<<"move disk "<<scale-britop+1<<" from \'b\' to \'a\'\n";

36 else

37 cout<<"move disk "<<scale-britop+1<<" from \'b\' to \'c\'\n";

38 }

39

40 if (last != dsttop && ((dsttop%2 && dsttop>britop) || ((dsttop%2==0) && dsttop>srctop)))

41 {

42 sdst.pop();

43 last = dsttop;

44 dsttop % 2 ? sbri.push(dsttop) : ssrc.push(dsttop);

45 if (dsttop % 2)

46 cout<<"move disk "<<scale-dsttop+1<<" from \'c\' to \'b\'\n";

47 else

48 cout<<"move disk "<<scale-dsttop+1<<" from \'c\' to \'a\'\n";

49 }

50 }

51 }

看上面的代碼好象復雜了點,不過主要還是因為判別的條件太復雜了,才會導致這段代碼這麽難懂。在這個while循環裏面有3個if語句都在判定當前的盤子是否可以被移動,如果可以移動就移動它並且打印出來。

對於壹個盤子要可以移動要滿足以下2個條件

1. 前壹次沒有被移動過也就是不能夠等於last

2. 盤子的編號必須要大於目標盤最上面的盤子的編號

這兩個條件都要滿足才能移動,可以證明在任何時候可以移動的盤子都是唯壹的。

為了便於和開始的方法比較,在輸出的時候對盤子的編號做了個轉換,還是把它還原成原來的編號的方法。也就是編號小的在上,編號大的在下。上面我這個寫法實在是太不簡潔了,希望有寫得更好的替換它。

3.遞歸的方法

盡管書上已經有遞歸的方法,不過我還是要給出我的遞歸的方法,作為參考。然後用於性能的比較。

3 #define move(disk,src,dst) cout<<"move disk "<<disk<<" from \'"<<src<<"\' to \'"<<dst<<"\'\n"

4 void hanoi_r(int size,char src,char dst,char bri)

5 {

6 if (size == 1)

7 move(size,src,dst);

8 else

9 {

10 hanoi_r(size-1,src,bri,dst);

11 move(size,src,dst);

12 hanoi_r(size-1,bri,dst,src);

13 }

14 }

4.各種方法的比較

有不同的實現方法,當然就有對比,我壹直以為非遞歸的方法要比遞歸的方法要快壹些,不過結果好象並不是這樣。

由於打印輸出需要消耗部少的時間,所以我就把它去掉了,只是改動我定義的宏就可以了。

堆棧

#define print_oprt(op)

遞歸

#define move(disk,src,dst)

表示這個打印操作什麽都不做。

下面是我在我的計算機上虛擬的Linux環境下用3種不同的方法解決規模為1-30的漢諾塔問題所花的時間的比較結果(單位是秒),妳也可以把這個程序下載到妳的計算機上去測試壹下。

Scale Stack Recursion Other (1-30)

1 0 0 0

2 0 0 0

3 0 0 0

4 0 0 0

5 0 0 0

6 0 0 0

7 0 0 0

8 0 0 0

9 0 0 0

10 0 0 0

11 0 0 0

12 0 0 0

13 0 0 0

14 0 0 0.01

15 0 0 0.01

16 0.02 0 0.01

17 0.03 0 0.03

18 0.05 0 0.05

19 0.12 0 0.12

20 0.23 0.01 0.23

21 0.49 0.01 0.47

22 0.95 0.04 0.89

23 1.92 0.07 1.87

24 3.8 0.15 3.55

25 7.65 0.3 7.52

26 15.2 0.6 14.24

27 30.49 1.2 29.7

28 61.11 2.41 57.24

29 111.15 4.29 97.56

30 201.09 7.72 184.32

用堆棧和其它的方法所花的時間比較接近,而用遞歸的速度卻是最快的。相差非常的大。到底是什麽原因呢,按理說應該不會有這麽大的差別哦。

總結了壹下,大概有以下原因:

1. STL本身的效率不是太高

STL功能強大了,效率上必然要受到壹定的影響

2. 遞歸的方式函數調用比較少,就是調用它本身,而其它方式函數調用比較多

從代碼中我們就可以看出,非遞歸方式調用函數的次數遠遠比遞歸方式多,每次移動操作都要調用好幾次函數,pop,push等,而遞歸方式,每次移動操作只調用本身壹次,故系統堆棧的負擔要小的多。

3. 對堆棧實現,涉及到對象的多次構造和析構,並且還有就是堆棧的多次重新分配也需要消耗不少的時間(STL中stack是順序存儲結構,當空間不夠用時,再向系統申請雙倍的空間)

附錄

上面提到的所以代碼我都已經把它壓縮好了,並且提供下載,

/zhengsh/download/hanoi.tar.gz

在readme文件中有比較詳細的說明。除了hanoi_cmp.c其它的文件都可以在windows,linux下通過編譯,我使用的是Linux下實現的,所以最好在Linux下重新編譯它們。

  • 上一篇:乒乓球淘汰賽制和單循環賽制的比賽方法是什麽?
  • 下一篇:visual basic 怎麽讓聲音隨程序播放?
  • copyright 2024編程學習大全網