1. 程式人生 > >漢諾塔詳解(初)

漢諾塔詳解(初)

漢諾塔 函數調用例題理解

漢諾塔(又稱河內塔)問題是源於印度一個古老傳說。大梵天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞著64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。並且規定,在小圓盤上不能放大圓盤,在三根柱子之間一次只能移動一個圓盤,利用函數,實現N片盤的漢諾塔的移動步驟

算法理解:

理解1:

宏觀上我們可以這樣理解:要將A上的n個盤子按照要求移動到C上,我們可以想到:將上邊的 n-1 的盤子移動到B上,將上邊的 n-2 個盤子移動到A,再將B上盤子移動到C上,然後將A上所有的盤子移動到C上,B做為踏板,這是比較簡單的理解,但是對於算法實現的過程,還是沒有弄透徹。

理解2:

我們知道當盤子數為n時,移動的次數應該為 2^n-1;這個有公式 H(n) = 2H(n-1) +1 得來,理解為:上邊的n-1個盤子先翻轉到B上,將最大的盤子移動到C上,花費1步,然後將B上的盤子翻轉到C上,花費2H(n-1)步。

後來美國的一位學者發現一種出人意料的簡單的算法,只要輪流兩步操作既可以實現:首先,把三張桌子按順序首尾相接的排列,形成一個環,然後對A上的盤子開始移動,順時針擺放成 A B C的順序:

若n為奇數,圓盤的移動順序是 A->C->B->A->C->B->A......... 即 間隔兩個步長移動 。此處的n代表盤子位的層數,比如說 3 層漢諾塔就是從下往上數第1、3 個盤子移動的順序。

若n為偶數,圓盤移動的順序為A->B->C->A->B->C->A..........即 間隔一個步長移動。對n的解釋同上 第二個盤子移動 A->B->C。


下邊是兩種類似的解題思路,唯一不同的是,三個位置變量的順序有差異,暫時由於學業的原因,沒有進行完善,還請擔待,後期會繼續完善。


#!/bin/bashcount=0n_1()
#步數的統計及盤子的移動都是通過第一個函數調用來完成,
{                let count++   
                                 echo "第${count}步:將${2}號圓盤從${1}移動到${3}"}n_2()
{                if [ $1 -eq 1 ];then
                     #如果位置變量1等於1的話,判斷成立,進行調用第一個函數
                     n_1 $2 1 $4
                else            
                     #不成立進行此步驟,此循環調用函數調用於判斷第一個盤子將移動到那個柱子上,循環過程下邊有說明。
                     n_2 $[$1-1] $2 $4 $3
                      #此函數調用,用於輔助上下函數調用進行輸出。
                     n_1 $2 $1 $4
                     #此步驟進行後續循環調用,上一個n_2負責把盤子從第一個柱子移走到第二個柱子上,
                     #這個n_2負責把第二個柱子上的盤子移動到第三個柱子上。
                     #中間的n_1負責最終要的一部將最大的盤子從第一個柱子移動到最後一個柱子上。
                     n_2 $[$1-1] $3 $2 $4
                fi
                }
                read -p "please input the number: " num
                n_2 $num X Y Z

     num=3
     n_2 3 X Y Z
            n_2 2 X Z Y
                n_2 1 X Y Z
                    n_1 X 1 Z
                        輸出:第1步:將1由X移到Z
                n_1 X 2 Y
                    輸出:第2步:將2由X移到Y
                n_2 1 Z X Y
                    n_1 Z 1 Y
                        輸出:第3步:將1由Z移到Y
            n_1 X 3 Z
                輸出:第4步:將3由X移到Z
            n_2 2 Y X Z
                n_2 1 Y Z X
                    n_1 Y 1 X
                        輸出:第5步:將1由Y移動X

                n_1 Y 2 Z
                    輸出:第6步:將2由Y移到Z

                n_2 1 X Y Z
                    n_1 X 1 Z
                        輸出:第7步:將1由X移到Z

二下邊方式還有待完善,能出結果,但是步驟詳解沒有做,僅做參考 。

#!/bin/bash
sun=0
funa() {
    let asd--
    let sun++
    echo "步數 : $sun   盤子 :  $1   移動方向: $2   ---->  $3 "  
}
funb() { 
    if [ $1  -eq  1 ];then  #當
        funa $1   $2   $4
        #     N   A     C
    else
        funb "$[$1-1]" $2  $4  $3
        if [   $? -eq  0 ];then
        echo "==================================================================$asd ---fun1"
        fi    
#1       N-1(4)    A    C   B  ------>  A(A)   B(C)    C(b)   
#3 B  a  c    
#    N-2(3)    A   B    C  ------->  A   B    C       Ab   Bc   Ca
#     2        a   c   b    ------->  A    Bc        Cb
#    1       a    c   b  ------    a   b   c
        funa $1  $2  $4
        if [ $? -eq 0  ];then
        echo "-=================================================================$asd ----fun2" 
        fi
        #1    N    A   C
        # N-1(4)  A   B
        # N-1(4)  B   C
        #N-2 (3)     #               b--a
#               c--b         
        funb "$[$1-1]" $3  $2  $4
        if [ $?  -eq  0  ];then
        echo "===================================================================$asd ----fun3"
        fi
#1   N-1 4      B   A    C   ---->  A(B)  B(A)  C(C )   
#3                       a  c   b    
#2   N-1 3      a   B    C      ---->   Ac    Ba      Cb
#      2       B   a  C             
#        1
    fi
}
read -p "shuru panshu : " asd
funb $asd A B C



漢諾塔詳解(初)