1. 程式人生 > >c++學習總結(二)——遞迴函式

c++學習總結(二)——遞迴函式

一、心得感悟

    關於函式之前有過總結,函式是在程式設計中為簡化主程式、使複雜程式簡單化的子程式。而遞迴函式則是一種特殊的函式。它是直接或間接呼叫的函式,通常可以把一個大型複雜的問題層層轉化為一個與原問題相似的規模較小的問題來求解。遞迴策略只需少量的程式就可以描述出解題過程所需要的多次重複計算。大大減少了程式的程式碼量。遞迴的能力在於有限的語句來定義物件的無限集合。用遞迴思想寫出的程式往往十分間接易懂。總而言之,使用遞迴函式是解決大型複雜問題必不可少的。

二、內容總結及例題

    下面結合部分程式碼來簡介一下遞迴函式。

例如

1.求x^n。首先可以把x^n分解成:

x^0=1       (n=0)

x^1=x*x^0(n=1)

x^2=x*x^1(n=2)

x^3=x*x^2(n=3)

……

因此將x^n轉化為:x*x^n-1,其中求x^n-1又用求x^n的方法進行求解。

分析:

<1>.定義子程式xn(int n)求x^n;如果n>=1,則遞迴呼叫xn(n-1)求x^n-1;

<2>.當遞迴呼叫到達n=0時終止呼叫。然後執行本“層”的後繼語句;

<3>.遇到子程式執行完後,就結束本次的呼叫,返回到上一“層”呼叫語句的地方,並執行其後繼語句;

<4>.繼續執行步驟3,從呼叫中逐“層”返回,最後返回到主程式。

程式如下:

#include<iostream>
using namespace std;
int xn(int);//定義遞迴函式
int x;
int main()
{
    int n;
    cin>>x>>n;
    cout<<x<<'^'<<n<<"="<<xn(x)<<endl;
    return 0;
}
int xn(int n)
{
    if(n==0)return 1;       //遞迴邊界
    else return x*xn(n-1);  //遞迴式

}

2.求x!

x!={    1        (x=0)

        x(x-1)    (x>0)

     }

分析x!=x(x-1)!,其中求(x-1)!仍採用求x!的方法,需要定義一個求x!的函式,逐級呼叫此函式,即:

當x=0時,x!=1;當x>0時,x!=x*(x-1)。

假設用函式f(x)表示x的階乘,當x=3時,f(3)的求解方法可表示為:f(3)=3*f(2)=3*2*f(1)=3*2*1*f(0)=3*2*1*1=6

<1>.定義函式:int f(int n)

如果n=0,則f=1;如果n>0,則繼續呼叫函式f=n*f(n-1);

<2>.返回主程式,列印f(x)的結果。

程式如下:

#include<iostream>
using namespace std;
int f(int);
int main()
{
    int x;
    cin>>x;
    cout<<x<<"!="<<f(x)<<endl;//主程式呼叫f(x)求x!
    return 0;
}
int f(int n)                                    //函式f(n)求n!
{
    return n==0?1:n*f(n-1);            //呼叫函式f(n-1)遞迴求(n-1)!

}

3.用遞迴方法求m,n兩數的最大公約數。(m>0,n>0)

求兩個數的最大公約數,這裡用輾轉相除法。

<1>.求m除以n的餘數;

<2>.如果餘數不為0,則讓m=n,n=餘數,重複步驟<1>,即呼叫子程式;

<3>.如果餘數為0,則終止呼叫子程式;

<4>.輸出此時的n值。

程式如下:

#include<iostream>
using namespace std;
int gcd(int,int);
int main()
{
    int m,n;
    cin>>m>>n;
    cout<<"gcd="<<gcd(m,n)<<endl;
    return 0;
}
int gcd(int m,int n)
{
    return n==0?m:gcd(n,m%n);

}

4.把M個同樣的蘋果放在N個同樣的盤子裡,允許有的盤子空著不放,問共有多少種不同的分法?(用K表示)5,1,1和1,5,1 是同一種分法。

本題我認為是有難度的題目,它涉及多種情況談論,少一種題目就會錯誤。

設f(m,n)為m個蘋果,n個盤子的放法數目,則先對n作討論,

當n>m:則必定有n-m個盤子永遠空著,去掉它們對擺放蘋果方法數目不產生影響。即 if(n>m) f(m,n) = f(m,m)

當n <= m:不同的放法可以分成兩類:含有0的方案數,不含有0的方案數

<1>.含有0的方案數,即有至少一個盤子空著,即相當於 f(m,n)=f(m,n-1);

<2>.不含有0的方案數,即所有的盤子都有蘋果,相當於可以從每個盤子中拿掉一個蘋果,不影響不同放法的數目,即f(m,n)=f(m-n,n).而總的放蘋果的放法數目等於兩者的和,即 f(m,n)=f(m,n-1)+f(m-n,n)

程式碼如下:

#include<bits/stdc++.h>
using namespace std;
int fun(int m,int n)        //m個蘋果放在n個盤子中共有幾種方法
{
    if(m==0||n==1)      //當m==0(沒有蘋果可放)時,定義為1种放法;
         return 1;          //當n=1時,所有蘋果都必須放在一個盤子裡,所以返回1;
    if(n>m)
         return fun(m,m);
    else
        return fun(m,n-1)+fun(m-n,n);
}
int main()
{
    int T,m,n;
    cin>>T;
    while(T--)
    {
        cin>>m>>n;
        cout<<fun(m,n)<<endl;
    }
    return 0;

}