遞迴與分治策略 1

2021-09-24 22:27:11 字數 4146 閱讀 9526

將求出的小規模的問題的解合併為乙個更大規模的問題的解,自底向上逐步求出原來問題的解。
分治法的設計思想是:將乙個難以直接解決的大問題,分割成一些規模較小的相同問題,以便各個擊破,分而治之。
遞迴的概念
直接或間接地呼叫自身的演算法稱為遞迴演算法。用函式自身給出定義的函式稱為遞迴函式
由分治法產生的子問題往往是原問題的較小模式,這就為使用遞迴技術提供了方便。在這種情況下,反覆應用分治手段,可以使子問題與原問題型別一致而其規模卻不斷縮小,最終使子問題縮小到很容易直接求出其解。這自然導致遞迴過程的產生。
分治與遞迴像一對孿生兄弟,經常同時應用在演算法設計之中,並由此產生許多高效演算法。
階乘函式可遞迴地定義為:

n! = 1      n = 0  (邊界條件

)

n! = n(n-1)!   n > 0  (遞迴方程

)

邊界條件與遞迴方程是遞迴函式的二個要素,遞迴函式只有具備了這兩個要素,才能在有限次計算後得出結果。

實現:

/*

*/#include

<

iostream

>

using

namespace

std;

//factorial implement by recursive

long

factorial_recursive(

long

n)//

factorial implement by loop

long

factorial_loop(

long

n)int

main()

return0;

}

無窮數列1,1

,2,3

,5,8

,13,21

,34,55

,……,稱為fibonacci

數列。它可以遞迴地定義為:

f(n) = 1                n = 0 (邊界條件

)

f(n) = 1            n = 1 (遞迴方程

)

f(n) = f(n - 1) + f(n - 2)      n > 2 (遞迴方程

)

實現:

/*

*/#include

<

iostream

>

using

namespace

std;

//fibonacci implement by recursive

long

fibonacci_recursive(

long

n)//

fibonacci implement by loop

long

fibonacci_loop(

long

n)return

result;

}int

main()

例3  ackerman函式

當乙個函式及它的乙個變數是由函式自身定義時,稱這個函式是雙遞迴函式

ackerman函式

a(n,

m)定義如下:

a(1,0) = 2

a(0,m) = 1           m >= 0

a(n,0) = n + 2         n >= 2

a(n,m) = a(a(n-1,m),m-1)    n,m >= 1

前2例中的函式都可以找到相應的非遞迴方式定義:

本例中的ackerman

函式卻無法找到非遞迴的定義。

a(n,

m)的自變數

m的每乙個值都定義了乙個單變數函式:

m = 0時,

a(n,0)=n+2

m = 1時,

a(n,1)=a(a(n-1,1),0) = a(n-1,1)+2

,和 a(1,1)=2

故a(n,1)=2*n

m = 2時,

a(n,2) = a(a(n-1,2),1)=2a(n-1,2)

,和a(1,2)=a(a(0,2),1)=a(1,1)=2

,故a(n,2)= 2^n 。

m = 3時,類似的可以推出

m = 4時,

a(n,4)

的增長速度非常快,以至於沒有適當的數

學式子來表示這一函式。

實現:

/*

*/#include

<

iostream

>

using

namespace

std;

//ackerman implement

long

ackerman(

long

n,long

m)int

main()

例4  

排列問題

設計乙個遞迴演算法生成n

個元素的全排列。

設r=是要進行排列的

n個元素,

ri=r-

。 集合x

中元素的全排列記為

perm(x)。

(ri)perm(x)表示在全排列

perm(x)

的每乙個排列前加上字首得到的排列。

r的全排列可歸納定義如下: 

當n=1

時,perm(r)=(r)

,其中r

是集合r

中唯一的元素;

當n>1

時,perm(r)

由(r1)perm(r1)

,(r2)perm(r2)

,…,(rn)perm(rn)

構成。

/*

*/#include

<

iostream

>

#include

<

vector

>

#include

<

iterator

>

using

namespace

std;

/*使用遞迴實現

* 遞迴產生所有字首是list[0:k-1],

* 且字尾是list[k,m]的全排列的所有排列

* 呼叫演算法perm(list,0,n-1)則產生list[0:n-1]的全排列

*/template

<

class

t>

void

perm_recursion(t list,

intk,

intm)

else}}

//非遞迴實現(可參照stl next_permutation原始碼)

template

<

class

t>

void

perm_loop(t list,

intlen)}}

intmain()

;cout

<<

"permutation implement by recursion:

"<<

endl;

perm_recursion(list,0,

2);cout

<<

endl;

cout

<<

"permutation implement by loop:

"<<

endl;

perm_loop(list,3);

cout

<<

endl;

return0;

}

遞迴與分治策略

1 全排列問題 設r n 是要進行排列的n個元素。集合x中元素的全排列記為perm x 求r n 的全排列perm r n 用遞迴演算法求解 1 找出遞迴子結構性質 即原問題的解包含了子問題的解,且子問題的描述與原問題相同。這就可以用子問題的解來構造原問題的解。設r i r n 這是乙個子問題。設 ...

遞迴與分治策略

1.遞迴 直接或間接地呼叫自身的演算法稱為遞迴演算法。用函式自身給出定義的函式稱為遞迴函式。1 階乘函式 include using namespace std int main int factorial int n 2 fibonacci數列 include using namespace st...

分治策略與遞迴

先看 資料結構與演算法分析 中對分治策略的解釋 把問題分成兩個大致相等的子問題,然後再遞迴地對他們進行求解,這是 分 治 階段將兩個子問題的解合併到一起並可能再做些少量的附加工作,最後得到整個問題的解。由定義可以看出,分治需要進行兩步操作 分 將問題恰當的劃分為需要迭代處理的兩個子問題,治 將兩個子...