程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 重拾算法之路——遞歸與分治基礎

重拾算法之路——遞歸與分治基礎

編輯:C++入門知識

重拾算法之路——遞歸與分治基礎


 

 

這個周末家裡有點事,回了趟家,就斷了一些學習計劃。。

抓緊補上!

 

第一個算法——遞歸與分治

都知道,分治算法基本思想是

將一個難以直接解決的問題,分割成一些規模小的相同問題,以便各個擊破,分而治之,

這樣,我們就可以將一個復雜的算法,類型不變,規模越來越小,最終使子問題容易求解,由此引出遞歸算法。

其實,分治和遞歸像一對孿生兄弟,經常可以同時使用在算法設計之中,並由此產生許多高效的算法。

 

一、遞歸

概念:直接或間接的調用自身的算法稱為遞歸算法,用函數自身給出定義的函數稱為遞歸函數。

下面列出幾個遞歸的經典例子:

① 階乘

定義:

n!等於 1 當n=0

等於n(n-1)! 當n>0

 

int  factorial(int n)
{
    if( n == 0 )    return 1;
    return n*factorial(n-1);
}

②Fibonacci數列

 

一個無窮的數列,序列為:1,1,2,3,5,8,13,21,34,55....

定義為:

F(n)= 1 當n=0

=1 當n=1

=F(n-1)+F(n-2) 當n>1

 

int fibonacci(int n)
{
    if( n <= 1 )    return 1;
    return fibonacci(n-1)+fibonacci(n-2);
}

 

 

③Ackerman函數

這是一個雙遞歸函數,當一個函數及它的一個變量由函數自身定義時,稱這個函數為雙遞歸函數。

Ackerman函數A(n,m) 有兩個獨立的整型變量m≥0,n≥0,其定義如下:

A(1,0) = 2 m≥0

A(0,m) = 1 n≥2

A(n,0) = n+2 n≥2

A(n,m) = A(A(n-1,m),m-1) n,m≥1

 

 

int Ackerman( int n , int m )
{
    if( n==1 && m==0 )    return 2;
    if( n==0 )    return 1;
    if( m==0 )    return n+2;
    return Ackerman( Ackerman(n-1,m),m-1);
}


 

④排列問題

對n個元素進行全排列,

當n=1時,Perm(P)=(r),其中r是集合R中唯一的元素

當n>1時,Perm(P)由(r1)Perm(R1),(r2)Perm(R2),.......,(rn)Perm(Rn)構成

 

 

template< class Type >

inline void Swap(Type& a,Type& b)
{
    Type temp = a;
    a = b;
    b = temp;
}

void Perm(Type list[],int k ,int m )
{
    if( k==m )
    {
        for( int i = 0 ; i <= m; ++i )    cout<

 

 

⑤整數劃分問題

將正整數n表示成一系列正整數之和,

n=n1+n2+...+nk(其中n1≥n2≥n3≥....≥nk)

例如,對於整數6的劃分:

6

5+1

4+2 4+1+1

3+3 3+2+1 3+1+1+1

2+2+2 2+2+1+1 2+1+1+1+1

1+1+1+1+1+1

總共11種劃分

按照最大加數n1不大於m的劃分個數記作q(n,m),可以建立如下遞歸關系:

<1> q(n,1) = 1 , n≥1—— 當最大加數n1不大於1時,任何正整數n只有一種劃分形式

<2> q(n,m)=q(n,n),n≥m—— 最大加數n1實際上不能大於n。因此q(1,m)=1

<3> q(n,m)=q(n,m-1)+q(n-m,m),n>m>1—— 正整數n的最大加數n1不大於m的劃分由n1=m的和n1≤m-1的劃分組成。

綜上所述,可以總結出:

q(n,m)=

1 n=1,m=1

q(n,n) n

1+q(n,n-1) n=m

q(n,m-1)+q(n-m,m) n>m>1

 

int q( int n , int m )
{
    if( (n<1) || (m<1) )    return 0;
    if( (n==1) || (m==1) )    return 1;
    if( n==m )    return q(n,m-1)+1;
    return q(n,m-1)+q(n-m,m);
}

 

 

⑥Hanoi塔問題

非常經典的一個遞歸問題,問題就不贅述了,直接寫算法:

 

void hanoi( int n , int a , int b , int c )
{
    if( n > 0 ){
        hanoi( n-1,a,c,b);
        move(a,b);
        hanoi( n-1,c,b,a);
    }
}


 

二、分治

之前也說過,分治法的基本思想就是,把一個規模大的問題,不斷分成相互獨立且與原問題相同的小規模問題。

它的算法設計模式如下:

 

divide-and-conquer(P)
{
    if( |P| <= n0 )    adhoc(P);
    divide P into smaller subinstances P1,P2,P3,...,Pk;
    for( i = 1 ; i <= k ; ++i )
        yi = divide-and-conquer(Pi);
    return merge(y1,y2,...,yk);
}

這其中

 

|P| 表示問題P的規模,

n0 為一阙值,表示當前問題P的規模不超過n0時,問題容易求解,不必再繼續分解。

adhoc(P) 是該分治法中的基本子算法,對於容易求解的問題可以直接求解

merge(y1,y2...yk) 是合並子算法,用於將P的子問題P1,P2,...,Pk的解y1,y2,...,yk合並為P的解

 

分治法的計算效率通常用遞歸方程來分析,對於上述設計模式,解|P|=n的問題所需的計算時間,有:

T(n) = O(1) 當n=1

kT(n/m)+f(n) 當n>1

 

 

 

以上就是遞歸和分治的一些基本思想和原則,接下來的博文會有具體例子來說明。

 

 

 

 

***************************************轉載請注明出處:http://blog.csdn.net/lttree********************************************

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved