漢諾塔遞歸與非遞歸

來源於http://www.cnblogs.com/AI-Algorithms/p/3357368.html
算法介紹:

其實算法非常簡單,當盤子的個數爲n時,移動的次數應等於2^n - 1(有興趣的可以自己證明試試看)。後來一位美國學者發現一種出人意料的簡單方法,只要輪流進行兩步操作就可以了。首先把三根柱子按順序排成品字型,把所有的圓盤按從大到小的順序放在柱子A上,根據圓盤的數量確定柱子的排放順序:若n爲偶數,按順時針方向依次擺放 A B C;

若n爲奇數,按順時針方向依次擺放 A C B。

(1)按順時針方向把圓盤1從現在的柱子移動到下一根柱子,即當n爲偶數時,若圓盤1在柱子A,則把它移動到B;若圓盤1在柱子B,則把它移動到C;若圓盤1在柱子C,則把它移動到A。

(2)接着,把另外兩根柱子上可以移動的圓盤移動到新的柱子上。即把非空柱子上的圓盤移動到空柱子上,當兩根柱子都非空時,移動較小的圓盤。這一步沒有明確規定移動哪個圓盤,你可能以爲會有多種可能性,其實不然,可實施的行動是唯一的。

(3)反覆進行(1)(2)操作,最後就能按規定完成漢諾塔的移動。

所以結果非常簡單,就是按照移動規則向一個方向移動金片:

如3階漢諾塔的移動:A→C,A→B,C→B,A→C,B→A,B→C,A→C

漢諾塔問題也是程序設計中的經典遞歸問題,下面我們將給出遞歸和非遞歸的不同實現源代碼。

●漢諾塔算法的遞歸實現C++源代碼

#include <fstream> 
#include <iostream> 
using namespace std; 
ofstream fout( "out.txt" ); 
void Move(int n,char x,char y) 
{ 
    fout<<"把"<<n<<"號從"<<x<<"挪動到"<<y<<endl; 
} 
void Hannoi(int n,char a,char b,char c) 

{ 
    if(n==1) 
        Move(1,a,c); 
    else 
    { 
        Hannoi(n-1,a,c,b); 
        Move(n,a,c); 
        Hannoi(n-1,b,a,c); 
    } 
} 
int main() 
{ 
    fout<<"以下是7層漢諾塔的解法:"<<endl; 
    Hannoi(7,'a','b','c'); 
    fout.close(); 
    cout<<"輸出完畢!"<<endl; 
    return 0; 
}
●漢諾塔算法的遞歸實現C源代碼

#include<stdio.h> 
void hanoi(int n,char A,char B,char C) 
{ 
    if(n==1) 
    { 
          printf("Move disk %d from %c to %c\n",n,A,C); 
    } 
    else 
    { 
          hanoi(n-1,A,C,B); 
          printf("Move disk %d from %c to %c\n",n,A,C); 
          hanoi(n-1,B,A,C); 
    } 
} 

void main() 
{ 
    int n; 
    printf("請輸入數字n以解決n階漢諾塔問題:\n"); 
    scanf("%d",&n); 
    hanoi(n,'A','B','C'); 
}
●漢諾塔算法的非遞歸實現C++源代碼

#include <iostream> 
using namespace std; 
//圓盤的個數最多爲64 
const int MAX = 64; 
//用來表示每根柱子的信息 
struct st{ 
    int s[MAX]; //柱子上的圓盤存儲情況 
    int top;     //棧頂,用來最上面的圓盤 
    char name;     //柱子的名字,可以是A,B,C中的一個 
    int Top()    //取棧頂元素 
    { 
        return s[top]; 
    } 
    int Pop()    //出棧 
    { 
     return s[top--]; 
    } 
    void Push(int x)    //入棧 
    { 
     s[++top] = x; 
    } 
} ; 
long Pow(int x, int y);     //計算x^y 
void Creat(st ta[], int n); //給結構數組設置初值 
void Hannuota(st ta[], long max);     //移動漢諾塔的主要函數 
int main(void) 
{ 
    int n;    
    cin >> n;                     //輸入圓盤的個數 
    st ta[3];                     //三根柱子的信息用結構數組存儲 
    Creat(ta, n);                 //給結構數組設置初值 
    long max = Pow(2, n) - 1;    //動的次數應等於2^n - 1 
    Hannuota(ta, max);            //移動漢諾塔的主要函數 
    system("pause"); 
    return 0; 
} 
void Creat(st ta[], int n) 
{ 
    ta[0].name = 'A'; 
    ta[0].top = n-1; 
    //把所有的圓盤按從大到小的順序放在柱子A上    
    for (int i=0; i<n; i++) 
        ta[0].s[i] = n - i; 
    //柱子B,C上開始沒有沒有圓盤 
    ta[1].top = ta[2].top = 0;
     for (int i=0; i<n; i++) 
        ta[1].s[i] = ta[2].s[i] = 0; 
        //若n爲偶數,按順時針方向依次擺放 A B C    
    if ( n%2 == 0) 
    {    
        ta[1].name = 'B'; 
     ta[2].name = 'C'; 
    } 
    else //若n爲奇數,按順時針方向依次擺放 A C B 
    { 
        ta[1].name = 'C'; 
     ta[2].name = 'B'; 
    } 
} 
long Pow(int x, int y) 
{ 
    long sum = 1; 

    for (int i = 0; i < y; i++) 
        sum *= x; 

    return sum; 
} 
void Hannuota(st ta[], long max) 
{ 
    int k = 0;     //累計移動的次數 
      int i = 0; 
      int ch; 
      while (k < max) 
      { 
        //按順時針方向把圓盤1從現在的柱子移動到下一根柱子 
        ch = ta[i%3].Pop(); 
         ta[(i+1)%3].Push(ch); 
           cout << ++k << ": " << "Move disk " << ch << " from " 
           << ta[i%3].name <<" to " << ta[(i+1)%3].name << endl; 
           i++; 
           //把另外兩根柱子上可以移動的圓盤移動到新的柱子上 
           if (k < max) 
           { 
            //把非空柱子上的圓盤移動到空柱子上,當兩根柱子都爲空時,移動較小的圓盤 
            if (ta[(i+1)%3].Top() == 0 || ta[(i-1)%3].Top() > 0 
                && ta[(i+1)%3].Top() > ta[(i-1)%3].Top()) 
            { 
                ch = ta[(i-1)%3].Pop(); 
                ta[(i+1)%3].Push(ch); 
                cout << ++k << ": " << "Move disk " << ch << " from " 
                << ta[(i-1)%3].name << " to " << ta[(i+1)%3].name << endl; 
            } 
            else 
         { 
                   ch = ta[(i+1)%3].Pop(); 
                   ta[(i-1)%3].Push(ch); 
                   cout << ++k << ": " << "Move disk " << ch << " from " 
                   << ta[(i+1)%3].name << " to " << ta[(i-1)%3].name << endl; 
            } 
         } 
    } 
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章