1. 程式人生 > >演算法總結之遞推與遞迴

演算法總結之遞推與遞迴

遞推演算法

遞迴演算法大致包括兩方面的內容:1)遞迴起點 ; 2)遞迴關係

遞推起點

遞迴起點一般由題目或者實際情況確定,不由遞迴關係推出。如果無法確定遞迴起點,那麼遞迴演算法就無法實現。可見,遞迴起點是遞迴演算法中的重要一筆。

遞推關係

遞迴關係是遞迴演算法的核心。常見的遞迴關係有以下幾項:

  • 1)一階遞推;
  • 2)多階遞推;
  • 3)間接遞推;
  • 4)逆向遞推;
  • 5)多維遞推。

下面通過栗子來詳細介紹一下上述類別的遞推關係。

1. 一階遞推
在計算f(i)時,只用到前面項中的一項,如等差數列。公差為3的等差數列,其遞推關係為:

f(i)=f(i-1)+3

eg. 平面上10條直線最多能把平面分成幾部分?
分析:以直線數目為遞推變數,假定i條直線把平面最多分成f(i)部分,則f(i-1)表示i-1條直線把平面分成的最多部分。在i-1條直線的平面上增加直線i,易得i與平面上已經存在了的i-1條直線最多各有一個交點,即直線i最多被分成i段,而這i段將會依次將平面一分為二,即直線i將最多使平面多增加i部分。所以,遞推關係可表示為:f(i)=f(i-1)+i
易得當0條直線時,平面為1部分。所以f(0)=1為遞推起點。
上述分析可用下面程式碼表示(c++):

#define MAX 100
int f[MAX] //存放f(i)
int lines(int n){
//輸入n為直線數目
//輸出最多部分數
    int i;
    f(0)=1;
    for(i=1;i<=n;i++){
          f[i]=f[i-1]+3;
    }
    return f[i];
    }

2. 多階遞推
在計算f(i)時,要用到前面計算過的多項,如Fibonacci數列。
eg.求Fibonacci的第10項。
分析:總所周知,Fibonacci數列中的第n項等於第n-1項加上n-2項。所以遞推關係為
f(i)=f(i-1)+f(i-2);且f[0]=f[1]=1。
C++程式碼如下:

#define MAX 100
int f[MAX];
int fib(int n){
//輸入n為項數
//輸出第n個fib數
   int i;
   f[0]=0;
   f[1]=1;
   for(i=2;i<=n;i++){
         f[i]=f[i-1]+f[i-2];
         }
   return f[n]
   }

3. 間接遞推
在計算f[i]時需要中間量,而計算中間量要用到之前計算過的項。
eg.現有四個人做傳球遊戲,要求接球后馬上傳給別人。由甲先傳,並作為第一次傳球。求經過10次傳球,球仍回到發球人甲手中的傳球方式的種數。
分析:定義兩個狀態,1)當前球在甲上,經過i次傳球之後球仍在甲上,此狀況記為F,其傳球方式的種數為f(i);2)當前球不在甲手上,經過i次傳球之後球在甲手上,此狀態記為G,其傳球方式的種數為g(i)。
對於狀態1):甲傳出一個球之後,接球的人的狀態便變成G(i-1)了,由於甲可以傳給3個不同的人,所以f(i)=3g(i-1);
對於狀態2):持球者可以選擇把球傳給甲,此時是F(i-1)狀態;也可以把球傳給另外兩個人,即2

G(i-1)狀態。所以g(i)=f(i-1)+2*g(i-1).
計算遞推起點,由於甲第一次不可能把球傳給自己,所以f(1)=0;其他人要傳一次球就把球傳給甲,那只有一種方式(直接把球傳給甲),即g(1)=1.
上述遞推關係便是間接遞推。用c++實現如下:

#define MAX 100
int f[MAX];
int g[MAX];
int ball(int n){
//輸入n為傳球次數
//輸出為傳球方式的種數
    int i;
    f[1]=0;
    g[1]=0;
    for(i=2;i<=n;i++){
        f[i]=3*g[i-1];
        g[i]=f[i-1]+2*g[i-1];
        }
    return f[n];
    }

4. 逆向遞推
顧名思義,就是從後面開始往前推。
eg.硬幣下棋遊戲。棋盤上標有第0站,第1站...第100站,一開始棋子在第0站,棋手每次投一次硬幣,若硬幣正面向上,則往前跳兩站;否則,往前跳一站...直到棋子跳到第99站(勝利大本營),第100站(失敗大本營)時,遊戲結束。如果硬幣出現正反面的概率均為0.5,分別求出棋子到達勝利大本營和失敗大本營的概率。
分析:假設記從第i站開始,最後到達100站的概率為f(i)。而從第i站,投擲一次硬幣,有0.5的概率到達第i+1站,有0.5的概率到達i+2站。所以遞推關係為:f(i)=0.5f(i+1)+0.5f(i+2).
易得遞推起點f(100)=1,f(99)=0.因為到達99站,遊戲結束。
上述就是逆遞推的一個過程。c++實現如下:

#define MAX 100
double f[MAX];
double prob(){
//無輸入
//輸出為到達100站的概率
    int i;
    f[100]=1.0;
    f[99]=0;
    for(i=98;i.=0;i--){
        f[i]=0.5*f[i+1]+0.5*f[i+2];
        }
    return f[0];
    }

5. 多維遞推
元素處於一個多維矩陣中,遞推需要使用矩陣中其他位置的元素。
例子日後更新。

遞迴函式

在電腦科學中,如果一個函式的實現中,出現對函式自身的呼叫語句,則該函式稱為遞迴函式。
遞推演算法可以用遞迴函式來實現。一般來說迴圈遞推演算法比遞迴函式要快,但遞迴函式的可讀性更棒。
把上面的部分遞推演算法改寫成遞迴函式。
1)平面劃分

int lines(int i){
    if(i<=0)
        return 1;
    else
        return lines(i-1)+i;
        }

2)Fibonacci數

int fib(int i){
   if(i==0)
        return 0;
    if(i==1)
        return 1;
    else
        return fib(i-1)+fib(i-2);
    }

由上面的程式碼可以分析到,遞推起點在遞迴函式中起到了遞迴截止作用。

遞迴函式的執行過程

遞迴函式每次呼叫自身都會生成一個啟用幀(包含程式的引數、區域性變數、返回值、以及該程式執行完畢後返回上一層的指令地址等),同時把計算控制交給下一次呼叫。這些啟用幀存在在系統中先進後出的棧裡。所以,程式的遞迴呼叫過大的話,會引發棧溢位。

尾遞迴

在計算機科學裡,尾呼叫是指一個函式裡的最後一個動作是一個函式呼叫的情形:即這個呼叫的返回值直接被當前函式返回的情形。

上面說到遞迴函式需要在呼叫多次時需要保留很多啟用幀,這會引發棧溢位。但如果採用尾遞迴的話,就可以避免這個情況。因為尾遞迴在程式的最後動作只是呼叫函式,不涉及其他計算問題,所以可以優化刪去很多中間的啟用幀。
如上面遞迴函式fib(),其最後一步就涉及加法,所以不是尾遞迴,但可以把它改成尾遞迴。如下:

int fib(int n,int f1,int f2)
{
//初始f1=0;f2=1
    if(n==0)
        return f1;
    else
        return fib(n-1,f2,f1+f2)
    }

由上面程式碼可看到,函式的最後呼叫就是一個函式,不涉及其他計算。

小結

遞迴函式一定要有遞迴起點作為遞迴結束標誌。

相關推薦

演算法總結

遞推演算法 遞迴演算法大致包括兩方面的內容:1)遞迴起點 ; 2)遞迴關係 遞推起點 遞迴起點一般由題目或者實際情況確定,不由遞迴關係推出。如果無法確定遞迴起點,那麼遞迴演算法就無法實現。可見,遞迴起點是遞迴演算法中的重要一筆。 遞推關係 遞迴關係是遞迴演算法的核心。常見的遞迴關係有以下幾項: 1)一階遞推

算法總結

總結 c++代碼 不同的 否則 狀況 def 函數調用 n) ron 遞推算法 遞歸算法大致包括兩方面的內容:1)遞歸起點 ; 2)遞歸關系 遞推起點 遞歸起點一般由題目或者實際情況確定,不由遞歸關系推出。如果無法確定遞歸起點,那麽遞歸算法就無法實現。可見,遞歸起點是遞歸算

二分——臺階問題

洛谷 P1192 臺階問題 題目描述 有N級的臺階,你一開始在底部,每次可以向上邁最多K級臺階(最少1級),問到達第N級臺階有多少種不同方式。 輸出mod 100003後的結果 分析 與數樓梯

概念 遞迴:從已知問題的結果出發,用迭代表達式逐步推算出問題的開始的條件,即順推法的逆過程,稱為遞迴。 遞推:遞推演算法是一種用若干步可重複運算來描述複雜問題的方法。遞推是序列計算中的一種常用演算法。通常是通過計算機前面的一些項來得出序列中的指定象的值。 遞

歸 - 歸實現組合數型枚舉

\n width .org i+1 left row 下標 lse 輸出 從 1~n 這 n 個整數中隨機選出 m 個,輸出所有可能的選擇方案。 輸入格式 兩個整數 n,m ,在同一行用空格隔開。 輸出格式 按照從小到大的順序輸出所有方案,每行1個。 首先,同一

演算法其實很有趣——窮舉法、、分治、概率(演算法需有通用性)

窮舉法 雞兔同籠問題:今有雞兔同籠,上有35頭,下有94足,問雞兔各幾何? 這個問題曾經我的一個商人朋友跟我講起過,像大多數人一樣,我從數學的角度出發,設雞有 x 只,兔有 y 只, x + y = 35 並且 2*x + 4*y = 94,正當我忙於計算出結 果的時候,

hdu 2050 第一場基礎演算法 折線分平面

題目連結hdu2050 程式碼如下: #include<cstdio> #include<algorithm> #include<iostream> using namespace std; int coun(int n) { if(n==1)

Scrapy爬蟲教程URL解析爬取

前面介紹了Scrapy如何實現一個最簡單的爬蟲,但是這個Demo裡只是對一個頁面進行了抓取。在實際應用中,爬蟲一個重要功能是”發現新頁面”,然後遞迴的讓爬取操作進行下去。 發現新頁面的方法很簡單,我們首先定義一個爬蟲的入口URL地址,比如《Scrapy入門教程》中的

step4_演算法_ACM組合 HDU1210 Eddy's 洗牌問題【函式+模擬】

第一遍編譯出錯。原來是next不能用,好惡心!!! 思路:記錄某個點下一步要走向的點的位置放在mnext[]中。 然後讓1按照規則走下去,直到1回到1點。走的步數就是步數。 #include&

玩轉演算法面試LeetCode演算法練習——二叉樹

目錄 104. 二叉樹的最大深度 給定一個二叉樹,找出其最大深度。 二叉樹的深度為根節點到最遠葉子節點的最長路徑上的節點數。 說明: 葉子節點是指沒有子節點的節點。 示例: 給定二叉樹 [3,9,20,null,n

[最全演算法總結]我是如何將演算法的複雜度優化到O(1)的

相信提到斐波那契數列,大家都不陌生,這個是在我們學習 C/C++ 的過程中必然會接觸到的一個問題,而作為一個經典的求解模型,我們怎麼能少的了去研究這個模型呢?筆者在不斷地學習和思考過程中,發現了這類經典模型竟然有如此多的有意思的求解演算法,能讓這個經典問題的時間複雜度降低到 \(O(1)\) ,下面我想對這個

練習二十八:回練習

問題:已知有五個小朋友一起。第五個朋友說自己比第四個大兩歲,問第四個人,他說他比第3個人大2歲,問第三個人,他說他比第二個人大兩歲,問第二個人,他說他比第一個人大2歲,問道最後一個人時,他說他10歲 求第五個人年齡是多少 1 def age_old(n): 2 if n == 1: 3

Fibonacci數列-

Fibonacci數列    無窮數列1,1,2,3,5,8,13,21,34,55,……,稱為Fibonacci數列。它可以遞迴地定義為: 第n個Fibonacci數可遞迴地計算如下: int fibonacci(int n)    {        if (

機器學習演算法總結XGBoost(下) 實戰調參

寫在前面 當時想學習XGBoost這個演算法就是因為研究生課題需要,現在終於可以試一試啦,希望真的像大家說的那麼強(據說是很多資料科學家的ultimate weapon)。XGBoost原理已在前一篇有過說明:機器學習演算法總結之XGBoost(上) 1.

箱子,

tmp 一個數 sta urn pos 遞歸實現 一個 space iostream 遞推代碼 1 #include <vector> 2 #include <iostream> 3 #include <stack>

對設計模式的總結簡單工廠策略模式

mage 建立 不變 href catch nag 實現類 初步 cti 前言 面向對象編程追求的本質-提高擴展性、可維護性、靈活性和復用性。合理利用面向對象6個原則,能夠很好的達到要求。如何利用好就是至關重要的了,前人總結了23+個設計模式能夠讓初學者更容易

poj1163 - DP歸寫法

end calculate base main blog can idt integer field 本題超鏈接:http://poj.org/problem?id=1163 The Triangle Time Limit: 1000MS Memory Limi

python 歸函數

body 數的本質 簡單的 png sys def 過程 你是 http 遞歸的定義——在一個函數裏再調用這個函數本身 現在我們已經大概知道剛剛講的story函數做了什麽,就是在一個函數裏再調用這個函數本身,這種魔性的使用函數的方式就叫做遞歸。 剛剛我們就已經寫了一個最簡單

HDU 2044(&歸_A題)解題報告

多少 size 思路 pri pan -c mat lis log 題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=2044 ---------------------------------------------------

UVALive 7431(&歸_C題)解題報告

body alt 維度 can mat char ref tps sed 題目鏈接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_