2011年10月23日 星期日

Recursive

http://www.programmer-club.com/pc2020v5/Forum/ShowSameTitleN.asp?URL=N&board_pc2020=general&id=2830
作者 : chiuinan2(青衫)

(1) recursive algorithm:

Procedure HANOI(A,B,C,n) // 將n個環從A移到B //
    if n<=0 then 
        print("error")
    else if n=1 then 
        print(A,"→",B)
    else
       [ call HANOI(A,C,B,n-1); 
         print(A,"→",B);
         call HANOI(C,B,A,n-1) ]
end

設計的主要觀念為:
    1.將A柱中前n-1個環搬到C柱中暫置。(呼叫自己)
    2.將A柱中剩下最大的環搬到B柱中。
    3.將C柱中的n-1個環搬到B柱中。(呼叫自己)

(2)將recursive改成non-recursive的做法有很多種。如果已經知道recursive algorithm的話,最正統的方法便是直接將它化成non-recursive的形式。由recursive algorithm化成non-recursive algorithm的方法如下:

  1.在程式開頭處標上一個label。
  2.在每個呼叫自己的敘述的下一個敘述前,各標上一個label。
  3.把每個呼叫自己的敘述代換成一個將目前狀態push到stack的敘述,以及將程式參數改變的敘述,然後跳回程式的開頭。
  4.將每個返回敘述變成檢查stack的敘述,只有在stack為空時才能返回,否則必須pop出以前的狀態,然後跳到應返回的位置繼續執行。

上述的方法其實是在模擬程序遞迴呼叫的方式,label的記錄則是要得知其返回位址。因此本題的non-recursive algorithm便可以化成:

Procedure HANOI(A,B,C,n) // 將n個環從A移到B //
step 1: 
    if n<=0 then 
        print("error")
    else if n=1 then 
        print(A,"→",B)
    else
        [ push(A,B,C,n-1,2);
          (A,B,C,n)←(A,C,B,n-1);
          goto step 1;
step 2:
          print(A,"→",B);
          push(A,B,C,n-1,3);
          (A,B,C,n)←(C,B,A,n-1);
          goto step 1; ]
step 3: 
    if stack not empty then
        [ pop(A,B,C,n,ret_step);
          goto ret_step ]
end

這個方法所得出的algorithm雖然不是最佳的,但是卻保證一定正確。當然您也可以利用程式技巧將它化簡成沒有label的結構化程式。另外一種方式是要靠靈感的,可說是可遇而不可求。例如上述algorithm,其實可以寫成:

Procedure HANOI(A,B,C,n) // 將n個環從A移到B //
step 1:
    if n<=0 then
        print("error")
    else if n=1 then
        print(A,"→",B)
    else
        [ Push(C,B,A,n-1);
          Push(A,B,C,1);
          Push(A,C,B,n-1) ]
    if stack not empty then
        [ pop(A,B,C,n);
          goto step 1 ]
end

使用三個push敘述來模擬三次搬運,相當簡潔。這是從觀察它的呼叫方式和stack的關係所發覺的,並無規則可循。雖然這個algorithm相當簡潔,但是執行速度並不是最好的。主要的原因是在於模擬recursice call的stack push和pop次數太多,因而減低了執行的速度。如果我們所要求的是速度的話,則必須儘量不要用stack的結構來模擬,應該從分析該問題non-recursive關係著手。這種過程一般都相當冗煩,而且不一定能夠做得到。這裡我們只列舉別人研究的成果供讀者參考,並做為以後您將來寫程式時的一個目標。Hanoi塔問題的non-recursive關係如下:

沒有留言:

張貼留言