精品日产一匹二匹三匹四匹五匹-亚洲国产成人精品女人久久久久-国产小视频在线一区二区-亚洲成人自拍偷拍视频-久久精品av一区二区三区-亚洲熟少妇一区二区三区-国产欧美在线观看精品一区二区-黑人一区二区三区啪啪网站-日本熟妇乱人视频在线

首頁(yè)>>課題研究>> 漢諾塔問題的算法分析及C++實(shí)現(xiàn) 正文

漢諾塔問題的算法分析及C++實(shí)現(xiàn)

2010-06-24 16:05 孫小慧 今日文教6月21日十五版

漢諾塔問題的算法分析及C++實(shí)現(xiàn)

江蘇灌南縣  孫小慧

   摘要:該文對(duì)經(jīng)典的漢諾塔問題進(jìn)行了詳細(xì)的分析,給出了遞歸的和非遞歸的算法,并用c++語(yǔ)言對(duì)這兩種算法進(jìn)行了實(shí)現(xiàn)與比較。

    關(guān)鍵字 漢諾塔,遞歸算法,非遞歸算法

Algorithm Analysis and C++ Realization of Hanio Issue

Sun Xiaohui

      Abstract: This text carries on detailed analysis about classical Hanio issue ,then describe it with both Recursive algorithm and Non-recursive algorithm, provides realization of algorithm in C++.

KeywordsTower of hanoiRecursive algorithmNon-recursive algorithm

      一、 問題描述

問題提出:

設(shè)有三個(gè)塔柱(分別為A號(hào),B號(hào)和C號(hào))。初始時(shí),有個(gè)圓盤按自下向上、從大到小的次序疊置在塔上。現(xiàn)要將塔上的所有圓盤,借助于B塔,全部移動(dòng)到C塔上,且仍按照原來的次序疊置。移動(dòng)的規(guī)則如下:這些圓形盤只能在個(gè)塔間進(jìn)行移動(dòng),一次只能移動(dòng)一個(gè)盤子,且任何時(shí)候都不允許將較大的盤子壓在比它小的盤子的上面。要求如下:從鍵盤輸入初始圓形盤子個(gè)數(shù)n,用語(yǔ)言實(shí)現(xiàn)個(gè)盤子最佳移動(dòng)的全過程[1]

本題的目的是設(shè)計(jì)一個(gè)盤子移動(dòng)的方案,使得號(hào)塔上的所有盤子借助于B塔按照原來的次序移動(dòng)到C塔上,并且,要給出完整的盤子移動(dòng)的方案。下面我們從遞歸和非遞歸兩種方面進(jìn)行考慮[2]

       二、 遞歸解法及其C++實(shí)現(xiàn)

我們先來考慮下遞歸求解這個(gè)問題的情況:

假設(shè)共有n個(gè)盤子,無論n是多少,也不管怎么去移動(dòng)盤子(當(dāng)然是按規(guī)則來移動(dòng)),但在移動(dòng)的過程中,將始終會(huì)出現(xiàn)這樣的狀態(tài)情況:(n1)個(gè)盤子將會(huì)以自下向上、從大到小的次序疊置在塔上,這時(shí),A塔上第個(gè)盤子就能被輕而易舉地疊放到塔上;接著,再把塔上的共(n1)個(gè)盤子移動(dòng)到塔上,問題好像已經(jīng)解決。但,塔上(n1)個(gè)盤子怎么移動(dòng)到塔上呢芽這是要解決的第二個(gè)問題。同樣,不管我們?cè)趺匆苿?dòng),也將會(huì)出現(xiàn)這樣的狀態(tài)情況:(n2 個(gè)盤子將會(huì)以從上到下、從大到小的次序疊置在塔上,這時(shí),塔上第(n1 個(gè)盤子就能被輕而易舉放到塔上;接著,把塔上的共(n2)個(gè)盤子移動(dòng)到塔上。這樣,不斷深入,不斷細(xì)小化,最終,將到達(dá)僅有一個(gè)盤的情形,這時(shí),遞歸也就終止了,問題也得到了解決。通過以上分析,這里有很明顯的遞歸關(guān)系。

由此,可以給出漢諾塔問題的遞歸算法如下:

1. 當(dāng)僅有1個(gè)盤子時(shí),把這個(gè)盤子從A塔柱移動(dòng)到C塔柱上

2. 當(dāng)圓盤的個(gè)數(shù)多于1個(gè)時(shí),如下解決:

(1) 先將A塔柱上的(n-1)個(gè)圓盤通過C塔柱移動(dòng)到B塔柱上

(2) 再將A塔柱上的第n個(gè)圓盤直接移動(dòng)到C塔柱上

(3) 最后B塔柱上的(n-1)個(gè)圓盤通過A塔柱移動(dòng)到C塔柱上

該算法對(duì)應(yīng)的代碼如下:

void hanoi(int n,char a,char b,char c)

{

if(n==1){

cout<<a<<"->"<<c<<endl;

}

else {

hanoi(n-1,a,c,b);

cout<<a<<"->"<<c<<endl;

hanoi(n-1,b,a,c);

}

}

        三、 非遞歸解法及其C++實(shí)現(xiàn)

首先把三根柱子按順序排成品字型,把所有的圓盤按從大到小的順序放在柱子A上。

根據(jù)圓盤的數(shù)量確定柱子的排放順序:若n為偶數(shù),按順時(shí)針方向依次擺放 A B C;

(1)若n為奇數(shù),按順時(shí)針方向依次擺放 A C B。

按順時(shí)針方向把圓盤1從現(xiàn)在的柱子移動(dòng)到下一根柱子,即當(dāng)n為偶數(shù)時(shí),若圓盤1在柱子A,則把它移動(dòng)到B;若圓盤1在柱子B,則把它移動(dòng)到C;若圓盤1在柱子C,則把它移動(dòng)到A。

(2)接著,把另外兩根柱子上可以移動(dòng)的圓盤移動(dòng)到新的柱子上。

即把非空柱子上的圓盤移動(dòng)到空柱子上,當(dāng)兩根柱子都非空時(shí),移動(dòng)較小的圓盤
這一步?jīng)]有明確規(guī)定移動(dòng)哪個(gè)圓盤,你可能以為會(huì)有多種可能性,其實(shí)不然,可實(shí)施的行動(dòng)是唯一的。

(3)反復(fù)進(jìn)行(1)(2)操作,最后就能按規(guī)定完成漢諾塔的移動(dòng)[3]

C++代碼如下:

const int MAX = 64; //圓盤的個(gè)數(shù)最多為64

struct st{  //用來表示每根柱子的信息

      int s[MAX]; //柱子上的圓盤存儲(chǔ)情況

      int top; //棧頂,用來最上面的圓盤

      char name; //柱子的名字,可以是A,B,C中的一個(gè)

     

      int Top(){//取棧頂元素

            return s[top];

      }

      int Pop(){//出棧

            return s[top--];

      }

      void Push(int x){//入棧

            s[++top] = x;

      }

} ;

long Pow(int x, int y); //計(jì)算x^y
void Creat(st ta[], int n); //給結(jié)構(gòu)數(shù)組設(shè)置初值
void Hannuota(st ta[], long max); //移動(dòng)漢諾塔的主要函數(shù)

int main(void)
{

      int n;
      cin >> n; //輸入圓盤的個(gè)數(shù)      
      st ta[3]; //三根柱子的信息用結(jié)構(gòu)數(shù)組存儲(chǔ)
      Creat(ta, n); //給結(jié)構(gòu)數(shù)組設(shè)置初值

      long max = Pow(2, n) - 1;//動(dòng)的次數(shù)應(yīng)等于2^n - 1
      Hannuota(ta, max);//移動(dòng)漢諾塔的主要函數(shù)

      system("pause");
      return 0;
}

void Creat(st ta[], int n)
{

      ta[0].name = 'A';

      ta[0].top = n-1;

      for (int i=0;i<n;i++)//把所有的圓盤按從大到小的順序放在柱子A上

            ta[0].s[i] = n - i;            
      ta[1].top = ta[2].top = 0;//柱子B,C上開始沒有沒有圓盤
      for (int i=0; i<n; i++)

            ta[1].s[i] = ta[2].s[i] = 0;

           

      if (n%2 == 0) //若n為偶數(shù),按順時(shí)針方向依次擺放 A B C
      {
            ta[1].name = 'B';
            ta[2].name = 'C';
      }
      else  //若n為奇數(shù),按順時(shí)針方向依次擺放 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; //累計(jì)移動(dòng)的次數(shù)
      int i = 0;
      int ch;
      while (k < max)
      {
            //按順時(shí)針方向把圓盤1從現(xiàn)在的柱子移動(dòng)到下一根柱子
            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++;
            //把另外兩根柱子上可以移動(dòng)的圓盤移動(dòng)到新的柱子上
            if (k < max)
            {//把非空柱子上的圓盤移動(dòng)到空柱子上,當(dāng)兩根柱子都為空時(shí),移動(dòng)較小的圓盤
                  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;
                  }
            }
      }
}

       四、 比較與總結(jié)

漢諾塔問題是經(jīng)典的遞歸算法例子。本文給出了遞歸和非遞歸兩種解決漢諾塔問題的算法。遞歸的漢諾塔問題解法優(yōu)點(diǎn)是邏輯清晰,易于理解,可讀性好,算法語(yǔ)句少,也有助于理解遞歸的思想,但需要大量的棧空間,運(yùn)行效率不高。如果用非遞歸方法解決漢諾塔問題的算法,優(yōu)點(diǎn)是僅用少量的存儲(chǔ)空間克服了遞歸算法的不足,兼顧了時(shí)間與空間的效率,缺點(diǎn)是理解起來可能比較困難,可讀性也不是很好,在實(shí)際中,可根據(jù)需要選擇一種進(jìn)行解決。

 

   參考文獻(xiàn)

[1] 王春森.程序員教程[M]. 北京:清華大學(xué)出版社,2001-05

[2] 周敏. 漢諾塔問題的算法分析及C語(yǔ)言實(shí)現(xiàn)[j].電腦學(xué)習(xí),2009年10月

[3] 談祥柏 著.數(shù)學(xué)營(yíng)養(yǎng)菜[M]. 中國(guó)少年兒童出版社,2004-5-1

中華文教網(wǎng)手機(jī)版
? 中華文教網(wǎng)版權(quán)所有 中華文教網(wǎng)簡(jiǎn)介 投稿指南 聯(lián)系我們 tags 版權(quán)聲明 sitemap