to初學者:從漢諾塔問題深入理解遞歸算法思想


計算機專業學習編程語言學到遞歸時會舉一個漢諾塔問題的經典例子:有A,B,C三根柱子,A柱上按大小順序從下往上摞着n片圓盤,現在要將這些圓盤從A柱移至C柱,並保持上小下大的順序。移動規則如下:1、每次只能移動一個盤。2、大盤不能放在小盤上。

用非遞歸方法要一大串代碼,而遞歸方法就非常簡短。遞歸算法C語言代碼如下:

#include <stdio.h>
void hanoi(int dishs,char p1,char p2,char p3)
{
  if(dishs==1){
    printf("盤子從%c移動到%c\n",p1,p3);
  {
  else{
    hanoi(dishs-1,p1,p3,p2);
    printf("盤子從%c移動到%c\n",p1,p3);
    hanoi(dishs-1,p2,p1,p3);
  }
}
void main()
{
  int n;
  printf("輸入盤子的個數:\n");
  scanf("%d",&n);

  hanoi(n,'A','B','C');
}

 

算法思路是:先將第n個盤上面的n-1個盤移至B柱,再把最底的第n個盤移至C柱,然后把B柱上的n-1個盤移至C駐。問題來了,不是說每次只能移動一個盤嗎?怎么能把n-1個盤整體移動呢?

要說明這個問題,先看看一個更簡單的例子,等差數列問題:一個等差數列第一項是100,每項差值為3,即f(0)=100,f(n)=f(n-1)+3,求第n個數。用遞歸方法可以這樣寫:

int f(n)
{
  if(n==1)
    return 100;
  else
    return f(n-1) + 3;
}
void main()
{
  int n,r;
  printf("輸入要查詢的第n個數:\n");
  scanf("%d",&n);

  r=f(n);
  printf(r);
}

 

算法思路是:要求第n個數,必須先求出第n-1個數,要求第n-1個數,必須先求第n-2個數,直至第1個數可以直接求出,然后不斷反推求出第n個數。這就是遞歸的的思想,先傳‘遞’出去,再回‘歸’到本位。寫成劇本是這樣的,第n項對n-1項說:老板要查詢我的值,你告訴我你的值,我加上3就行了。n-1項說好啊,不過我也不知道我的值,我要再問問我的前項,它給我后我加上3就是我的值,我到時再給你。這個對話一直傳下去,直到首項的小弟弟告訴第2項的兄弟:我的值是100。這樣問題就全解決了。

現在再來看漢諾塔問題就容易理解了,劇本是這樣的,n層的盤子對上面的盤子說:你們全部挪到B柱,我再挪到C柱,然后你們再過來不就行了么。n-1層的盤子說:你說的簡單,每次只能挪1個盤呀,我們怎樣全部挪到B柱?n層盤子說:笨蛋,反正我最大,你們盡管放在我上面木有問題,你們完全可以無視我的存在。這樣你們n-1個盤全部挪到B柱,與我們n個盤全部挪到C柱所面臨的問題不是一樣的嗎?都是移柱的問題呀,你們還比我少了一個盤,問題復雜度還簡化了呢,你就照樣畫葫蘆就行了。n-1層的盤說:哇塞!說的對!上面n-2個盤聽好了,我們現在要全部挪到B柱,你們n-2個盤先全部挪到C柱,我再挪到B柱,然后你們再過來。這個對話一直往上傳直到最頂層,問題簡化為1個盤從A柱挪到C柱。解決了這個問題,其它問題也就全解決了。

總結:如果一個問題有層次自相似性,那么就可以用遞歸方法,不斷回溯簡化問題,直至找到初值然后倒推出結論。


免責聲明!

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



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