日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

递归算法实例讲解

發布時間:2025/3/16 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 递归算法实例讲解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文鏈接:http://www.cricode.com/3489.html

題圖:遞歸

在數學與計算機科學中,遞歸是指在函數的定義中使用函數自身的方法。
遞歸算法是一種直接或者間接地調用自身算法的過程。在計算機編寫程序中,遞歸算法對解決一大類問題是十分有效的,它往往使算法的描述簡潔而且易于理解。
遞歸算法解決問題的特點:
(1) 遞歸就是在過程或函數里調用自身。
(2) 在使用遞歸策略時,必須有一個明確的遞歸結束條件,稱為遞歸出口。
(3) 遞歸算法解題通常顯得很簡潔,但遞歸算法解題的運行效率較低。所以一般不提倡用遞歸算法設計程序。
(4) 在遞歸調用的過程當中系統為每一層的返回點、局部量等開辟了棧來存儲。遞歸次數過多容易造成棧溢出等。所以一般不提倡用遞歸算法設計程序。在實際編程中尤其要注意棧溢出問題。

借助遞歸方法,我們可以把一個相對復雜的問題轉化為一個與原問題相似的規模較小的問題來求解,遞歸方法只需少量的程序就可描述出解題過程所需要的多次重復計算,大大地減少了程序的代碼量。但在帶來便捷的同時,也會有一些缺點,也即:通常用遞歸方法的運行效率不高。

遞歸算法實例

1.Fibonacci函數

講到遞歸,我們最先接觸到的一個實例便是斐波那契數列。
斐波那契數列指的是這樣一個數列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, …
特別指出:第0項是0,第1項是第一個1。
這個數列從第二項開始,每一項都等于前兩項之和。
斐波那契數列遞歸法實現:

123456789101112int Fib(int n){????if(n<1)????{????????return -1;????}????if(n == 1|| n == 2)????{????????return 1;????}????return Fib(n-1)+Fib(n-2);}

?

2.漢諾塔問題

漢諾塔示意圖

漢諾塔是根據一個傳說形成的數學問題:
有三根桿子A,B,C。A桿上有N個(N>1)穿孔圓盤,盤的尺寸由下到上依次變小。要求按下列規則將所有圓盤移至C桿:
每次只能移動一個圓盤;
大盤不能疊在小盤上面。
提示:可將圓盤臨時置于B桿,也可將從A桿移出的圓盤重新移回A桿,但都必須遵循上述兩條規則。
問:如何移?最少要移動多少次?

最早發明這個問題的人是法國數學家愛德華·盧卡斯。

傳說印度某間寺院有三根柱子,上串64個金盤。寺院里的僧侶依照一個古老的預言,以上述規則移動這些盤子;預言說當這些盤子移動完畢,世界就會滅亡。這個傳說叫做梵天寺之塔問題(Tower of Brahma puzzle)。但不知道是盧卡斯自創的這個傳說,還是他受他人啟發。
若傳說屬實,僧侶們需要264 ? 1步才能完成這個任務;若他們每秒可完成一個盤子的移動,就需要5849億年才能完成。整個宇宙現在也不過137億年。
這個傳說有若干變體:寺院換成修道院、僧侶換成修士等等。寺院的地點眾說紛紜,其中一說是位于越南的河內,所以被命名為“河內塔”。另外亦有“金盤是創世時所造”、“僧侶們每天移動一盤”之類的背景設定。
佛教中確實有“浮屠”(塔)這種建筑;有些浮屠亦遵守上述規則而建。“河內塔”一名可能是由中南半島在殖民時期傳入歐洲的。

以下是漢諾塔問題的遞歸求解實現:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 /* * Project???? : hannoi * File????????: main.cpp * Author??????: iCoding * * Date & Time : Sat Oct 06 21:01:55 2012 * */ usingnamespacestd; #include <iostream> #include <cstdio> voidhannoi(intn,charfrom,charbuffer,charto) { ????if(n==1) ????{ ????????cout<<"Move disk "<<n<<" from "<<from<<" to "<<to<<endl; ????} ????else ????{ ????????hannoi(n-1,from,to,buffer); ????????cout<<"Move disk "<<n<<" from "<<from<<" to "<<to<<endl; ????????hannoi(n-1,buffer,from,to); ????} } intmain() { ????intn; ????cin>>n; ????hannoi(n,'A','B','C'); ????return0; }

更詳細解析請參考:編程解決漢諾塔問題

3.二叉樹遍歷

計算機科學中,二叉樹是每個節點最多有兩個子樹的樹結構。通常子樹被稱作“左子樹”(left subtree)和“右子樹”(right subtree)。

一顆簡單的二叉樹

二叉樹的遍歷分為三種:前(先)序、中序、后序遍歷。

設L、D、R分別表示二叉樹的左子樹、根結點和遍歷右子樹,則先(根)序遍歷二叉樹的順序是DLR,中(根)序遍歷二叉樹的順序是LDR,后(根)序遍歷二叉樹的順序是LRD。還有按層遍歷二叉樹。這些方法的時間復雜度都是O(n),n為結點個數。

假設我們有一個包含值的value和指向兩個子結點的left和right的樹結點結構。我們可以寫出這樣的過程

先序遍歷(遞歸實現):

1234visit(node)????print node.value????if node.left??!= null then visit(node.left)????if node.right != null then visit(node.right)

?中序遍歷(遞歸實現):

1 2 3 4 visit(node) ????ifnode.left??!=nullthenvisit(node.left) ????printnode.value ????ifnode.right!=nullthenvisit(node.right)

?后序遍歷(遞歸實現):

1234visit(node)????if node.left??!= null then visit(node.left)????if node.right != null then visit(node.right)????print node.value

4.字符串全排列

問題:

寫一個函數返回一個串的所有排列。

解析:

對于一個長度為n的串,它的全排列共有A(n, n)=n!種。這個問題也是一個遞歸的問題, 不過我們可以用不同的思路去理解它。為了方便講解,假設我們要考察的串是”abc”, 遞歸函數名叫permu。

思路一:

我們可以把串“abc”中的第0個字符a取出來,然后遞歸調用permu計算剩余的串“bc” 的排列,得到{bc, cb}。然后再將字符a插入這兩個串中的任何一個空位(插空法), 得到最終所有的排列。比如,a插入串bc的所有(3個)空位,得到{abc,bac,bca}。 遞歸的終止條件是什么呢?當一個串為空,就無法再取出其中的第0個字符了, 所以此時返回一個空的排列。代碼如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 typedefvector<string>vs; vspermu(strings){ ????vsresult; ????if(s==""){ ????????result.push_back(""); ????????returnresult; ????} ????stringc=s.substr(0,1); ????vsres=permu(s.substr(1)); ????for(inti=0;i<res.size();++i){ ????????stringt=res[i]; ????????for(intj=0;j<=t.length();++j){ ????????????stringu=t; ????????????u.insert(j,c); ????????????result.push_back(u); ????????} ????} ????returnresult;//調用result的拷貝構造函數,返回它的一份copy,然后這個局部變量銷毀(與基本類型一樣) }

?

思路二:

我們還可以用另一種思路來遞歸解這個問題。還是針對串“abc”, 我依次取出這個串中的每個字符,然后調用permu去計算剩余串的排列。 然后只需要把取出的字符加到剩余串排列的每個字符前即可。對于這個例子, 程序先取出a,然后計算剩余串的排列得到{bc,cb},然后把a加到它們的前面,得到 {abc,acb};接著取出b,計算剩余串的排列得到{ac,ca},然后把b加到它們前面, 得到{bac,bca};后面的同理。最后就可以得到“abc”的全序列。代碼如下:

12345678910111213141516vs permu1(string s){????vs result;????if(s == ""){????????result.push_back("");????????return result;????}????for(int i=0; i<s.length(); ++i){????????string c = s.substr(i, 1);????????string t = s;????????vs res = permu1(t.erase(i, 1));????????for(int j=0; j<res.size(); ++j){????????????result.push_back(c + res[j]);????????}????}????return result;}

更詳細講解請參考:寫一個函數返回一個串的所有排列

5.八皇后問題

問題:

經典的八皇后問題,即在一個8*8的棋盤上放8個皇后,使得這8個皇后無法互相攻擊( 任意2個皇后不能處于同一行,同一列或是對角線上),輸出所有可能的擺放情況。

解析:

8皇后是個經典的問題,如果使用暴力法,每個格子都去考慮放皇后與否,一共有264?種可能。所以暴力法并不是個好辦法。由于皇后們是不能放在同一行的, 所以我們可以去掉“行”這個因素,即我第1次考慮把皇后放在第1行的某個位置, 第2次放的時候就不用去放在第一行了,因為這樣放皇后間是可以互相攻擊的。 第2次我就考慮把皇后放在第2行的某個位置,第3次我考慮把皇后放在第3行的某個位置, 這樣依次去遞歸。每計算1行,遞歸一次,每次遞歸里面考慮8列, 即對每一行皇后有8個可能的位置可以放。找到一個與前面行的皇后都不會互相攻擊的位置, 然后再遞歸進入下一行。找到一組可行解即可輸出,然后程序回溯去找下一組可靠解。

我們用一個一維數組來表示相應行對應的列,比如c[i]=j表示, 第i行的皇后放在第j列。如果當前行是r,皇后放在哪一列呢?c[r]列。 一共有8列,所以我們要讓c[r]依次取第0列,第1列,第2列……一直到第7列, 每取一次我們就去考慮,皇后放的位置會不會和前面已經放了的皇后有沖突。 怎樣是有沖突呢?同行,同列,對角線。由于已經不會同行了,所以不用考慮這一點。 同列:c[r]==c[j]; 同對角線有兩種可能,即主對角線方向和副對角線方向。 主對角線方向滿足,行之差等于列之差:r-j==c[r]-c[j]; 副對角線方向滿足, 行之差等于列之差的相反數:r-j==c[j]-c[r]。 只有滿足了當前皇后和前面所有的皇后都不會互相攻擊的時候,才能進入下一級遞歸。

代碼如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include <iostream> usingnamespacestd; intc[20],n=8,cnt=0; voidprint(){ ????for(inti=0;i<n;++i){ ????????for(intj=0;j<n;++j){ ????????????if(j==c[i])cout<<"1 "; ????????????elsecout<<"0 "; ????????} ????????cout<<endl; ????} ????cout<<endl; } voidsearch(intr){ ????if(r==n){ ????????print(); ????????++cnt; ????????return; ????} ????for(inti=0;i<n;++i){ ????????c[r]=i; ????????intok=1; ????????for(intj=0;j<r;++j) ????????????if(c[r]==c[j]||r-j==c[r]-c[j]||r-j==c[j]-c[r]){ ????????????????ok=0; ????????????????break; ????????????} ????????if(ok)search(r+1); ????} } intmain(){ ????search(0); ????cout<<cnt<<endl; ????return0; }





總結

以上是生活随笔為你收集整理的递归算法实例讲解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。