采用遞歸和非遞歸方法求解Hanoi問題


目的:領會基本遞歸算法設計和遞歸到非遞歸的轉換方法

內容:編寫一個程序exp5-1.cpp,采用遞歸和非遞歸方法求解Hanoi問題,輸出三個盤片的移動過程

寫在前面

題目是昨天老師發在學習通上的,目前

解決了:

  1. Hanoi問題理解
  2. Hanoi遞歸算法及其實現

未解決的:

  1. Hanoi非遞歸算法及實現
    (PPT上是用棧來實現的,然而筆者對棧不熟...解決完再記上來吧)

以下就從解決了的兩個方面展開討論

Hanoi問題理解

筆者參考的是算法動態圖解app上的解釋,還挺直觀的:

簡單來說就是有X,Y,Z三個柱子,目標是將X柱子上的盤片移動到Y柱子上,同時要保持和X柱相同的順序。X柱子上盤片自下而上、由大到小放置着n個盤片,兩個要求:

Ⅰ. 一次只能移一個盤片

Ⅱ.不能把大盤片放在小盤片上

個人的理解:
首先,為了方便分析,將X柱上盤片自上而下依次編號為\(1,2...n\)

  • 當n=1時,即X柱上只有一個盤片,直接從X移動到Z,這是最簡單的情況
  • 當n=2 時,
    第一步,把1號移動到Y柱(因為要滿足要求Ⅱ,2號盤片必須第一個移動到Z柱上,那么必須把1號先移開,移動到哪里?肯定不能是Z柱,那么就是Y柱了)
    第二步,把2號盤移到Z柱
    第三步,把1號從Y柱移動到Z柱,完成!
  • 當n=3時,
    第一步,可以把1號,2號盤,通過Z柱移到Y柱,這在前面(n=2時)已經證明可行。
    第二步,把3號盤移到Y柱
    第三步,發現問題轉化為n=2的情況,即把1號,2號盤,從Y柱移動到Z柱,方法參見n=2,不再贅述

寫到這里,我們發現這個問題是可遞歸的,n個盤片的Hanoi問題可以通過n-1個盤片的Hanoi問題求得,抽象成數學語言就是$$f(n)=g(f(n-1),c_{n-1},
,f(1)=m_1$$

要求\(f(n)\),可先求\(f(n-1),f(n-2)...\),層層遞歸,直到\(f(1)\)


Hanoi遞歸算法及其實現
遞歸模型及遞歸算法
  • 設計遞歸模型

    可以看出遞歸模型分為遞歸體,遞歸出口兩個部分,其實就是高中數學數列,遞歸函數概念
  • 設計遞歸算法(以本題為例)
    把盤片數,X柱,Y柱,Z柱分別抽象成自定義函數的四個參數n,X,Y,Z
void Hanoi1(int n,char X,char Y,char Z)

分別用if語句,else語句描述遞歸出口與遞歸體

  • 算法代碼:

//遞歸法
void Hanoi1(int n,char X,char Y,char Z){

    
        if(n==1){
        printf("\t將第%d個盤片從%c移動到%c\n",n,X,Z);//遞歸出口,當只有一個盤片時     }
        else {
        Hanoi1 (n-1,X,Z,Y);//將n-1個盤片,通過z,從x移動到y
        printf ("\t把第%d個盤片從%c移動到%c\n",n,X,Z);//將第n個盤片,從x移動到z
        Hanoi1 (n-1,Y,X,Z);//將n-1個盤片,通過x,從y移動到z
        
        }
}

Hanoi遞歸算法的實現

理解了算法代碼的實現,接下來就就是"搬磚"階段了

在main()函數里分別初始化三個參數的值,然后調用Hanoi1()就可以了

完整代碼:

#include <iostream>
using namespace std;

//遞歸法
void Hanoi1(int n,char X,char Y,char Z){

    
        if(n==1){
        printf("\t將第%d個盤片從%c移動到%c\n",n,X,Z);//遞歸出口,當只有一個盤片時
    }
    else {
        Hanoi1 (n-1,X,Z,Y);//將n-1個盤片,通過z,從x移動到y
        printf ("\t把第%d個盤片從%c移動到%c\n",n,X,Z);//將第n個盤片,從x移動到z
        Hanoi1 (n-1,Y,X,Z);//將n-1個盤片,通過x,從y移動到z
        
    }
}
int main() {
    int n=3;
    char X='x',Y='y',Z='z';
    cout <<"遞歸法過程:"<<endl;
    Hanoi1 (n,X,Y,Z);
    return 0;
}

運行截圖:


寫在最后

在"搬磚"的過程中,出現了許多錯誤,變量未初始化(uninitialzing),函數未指名(not declared) ...原因在於沒有經歷完整的c語言編程過程,只是看教材的代碼,效率確實太低了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM