遞歸與分治

遞歸(Recursion):指函數(shù)的定義中調(diào)用函數(shù)自身的方法硕糊。

遞歸調(diào)用過程:


Recursion

舉個很好玩的栗子:



用遞歸調(diào)用輸出圖片上的字:

#include <stdio.h>
void Recursion(int depth){
    printf("抱著");
    if (!depth) printf("我的小鯉魚");
    else Recursion(--depth);
    printf("的我");
}
int main(){
    printf("嚇得我抱起了\n");
    Recursion(2);
    putchar('\n');
}

爬樓梯:

小明爬樓梯,他每次可以走一級或兩級臺階郎逃,輸入樓梯的級數(shù),求不同的走法數(shù)。
分析:n級臺階走法=先走一級后(n-1)級臺階走法+先走兩級后(n-2)級臺階走法,即f(n)=f(n-1)+f(n-2),邊界條件n=1 ,1 n=2, 2

int stairs(int n)
{
    if(n==1)return 1;
    else if(n==2)return 2;
    else return stairs(n-1)+stairs(n-2);
} 

放蘋果:

把M個相同的蘋果放在N個相同的籃子里宋光,允許有的籃子空著不放,問共有多少種不同放法炭菌?5罪佳,1,1和1黑低,5赘艳,1是同一種放法

  • 分析:設i個蘋果放在k個籃子里放法總數(shù)為f(i,k)則:
    k>i時,f(i,k)=f(i,i)克握,其他k-1個籃子為空
    k<=i時蕾管,總放法=有盤子為空的放法+沒有盤子為空的放法
    f(i,k)=f(i,k-1)+f(i-k,k)
    f(i,k-1)可以理解為拿出來一個籃子空著不放,這樣就變成了有盤子為空
    f(i-k,k)可以理解為拿出來k個蘋果放在每個籃子里玛荞,保證籃子不空娇掏,然后放剩下的i-k個蘋果。
int f(int m,int n)
{
  if(m==0)return 1;
  if(n<=0)return 0;
  if(n>m)return f(m,m);
  return f(m,n-1)+f(m-n,n);

算24:

給出4個小于10的整數(shù)勋眯,可以使用加減乘除四種運算以及括號把這四個數(shù)連接起來得到一個表達式∮の啵現(xiàn)在的問題是是否存在一種方式使得表達式的值等于24

  • 分析:n個數(shù)算24,必須先有兩個數(shù)先算客蹋,剩下的問題就變成了n-1個數(shù)算24塞蹭,所以可以枚舉先算的兩個數(shù)以及運算方式
    邊界條件:一個數(shù)算24
#include <iostream>
#include <cmath>
using namespace std;
double a[5];
#define EPS 1e-6
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
bool count24(double a[],int n);

int main(int argc, char** argv) {
    for(int i=0;i<5;++i)cin>>a[i];
    while(a[0]!=0)
    {
        if(count24(a,4))cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
        for(int i=0;i<5;++i)cin>>a[i];
    }
    return 0;
}
bool isZero(double x)
{
    return (fabs(x-24)<=EPS);
}
bool count24(double a[],int n)
{
    if(n==1)return isZero(a[0]-24);
    double b[5];
    for(int i=0;i<n-1;++i)
    {
        for(int j=i+1;j<n;++j)
        {
            int m=0;
            for(int k=0;k<n;++k)
            {
                if(k!=i&&k!=j)
                {
                    b[m++]=a[k];
                }
            }
            b[m]=a[i]+a[j];
            if(count24(b,m+1))return true;
            b[m]=a[i]-a[j];
            if(count24(b,m+1))return true;
            b[m]=a[i]*a[j];
            if(count24(b,m+1))return true;
            if(!isZero(a[j]))
            {
                b[m]=a[i]/a[j];
                if(count24(b,m+1))return true;
            }
            if(!isZero(a[i]))
            {
                b[m]=a[j]/a[i];
                if(count24(b,m+1))return true;
            }
            
        }
    }
    return false;
}


分治(divide-and-conquer):將一個難以直接解決的大問題分割成一些規(guī)模較小的相同問題,以便各個擊破讶坯,分而治之番电。

適用條件:

  • 規(guī)模縮小到一定程度可以解決
  • 該問題可以分解為幾個規(guī)模較小的相同問題
  • 子問題的解可以合并成大問題的解
  • 子問題相互獨立

一般算法設計模式:

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

二分查找(binary Search):

問題描述:給定一個單調(diào)遞增的整數(shù)序列辆琅,問某個整數(shù)是否在序列中漱办。

//在數(shù)組a中查找x,n代表數(shù)組長度
int binarySearch(int *a,int n,int x)
{
    int low=0,high=n-1;
    int mid;
    while(low<=high)
    {
        mid=(low+high)/2;
        if(a[mid]==x){
            return mid;
        }
        else if(a[mid]<x)
        {
            low=mid+1;
        }
        else if(a[mid]>x)
        {
            high=mid-1;
        }
    }
    return -1;
}

歸并排序(Merge Sort):

歸并:將兩個有序的數(shù)組歸并成一個更大的有序數(shù)組婉烟。
歸并排序:先(遞歸地)將一個數(shù)組分成兩半分別排序娩井,然后將結果歸并起來。

//原地歸并似袁,將a[low,mid]和a[mid+1,high]合并為一個有序數(shù)組洞辣。
void merge(int *a,int low,int high)
{
    int mid = (low + high)/2;
    int i = low;
    int j = mid + 1;
    int aux[high-low+1];//輔助數(shù)組
    for(int k = 0;k<=high;++k)
    {
        aux[k] = a[k];
    }
    for(int k=0;k<=high;++k)
    {
        if(i>mid)a[k]=aux[j++];//左半邊用完咐刨,將右半邊剩余元素復制到a數(shù)組中
        else if(j>high)a[k]=aux[i++];//右半邊用完
        else if(aux[i]<aux[j])a[k]=aux[i++];
        else a[k]=aux[j++];
    }
}
//將數(shù)組a[low,high]排序。
void mergeSort(int* a,int low,int high)
{
    if(high>low){
        int mid=(high+low)/2;
        mergeSort(a,low,mid);
        mergeSort(a,mid+1,high);
        merge(a,low,mid,high);
    }
}
mergeSort

快速排序(quick Sort):

步驟:

  1. 從數(shù)列中挑出一個元素扬霜,稱為"基準"(pivot)定鸟。
  2. 重新排序數(shù)列,所有比基準值小的元素擺放在基準前面著瓶,所有比基準值大的元素擺在基準后面(相同的數(shù)可以到任何一邊)联予。在這個分區(qū)結束之后,該基準就處于數(shù)列的中間位置蟹但。這個稱為分區(qū)(partition)操作躯泰。
  3. 對”基準”左邊和右邊的兩個子集,不斷重復第一步和第二步华糖,直到所有子集只剩下一個元素為止
void quickSort(int* a,int low,int high)
{
    if(high<=low)return;
    int j=partition(a,low,high);
    quickSort(a,low,j-1);
    quickSort(a,j+1,high);
}

int partition(int* a,int low,int high)
{
    int i=low;
    int j=high+1;
    int v=a[low];
    while(true)
    {
        while(a[++i]<v)if(i==high)break;
        while(v<a[--j])if(j==low)break;
        if(i>=j)break;
        swap(a[i],a[j]);
    }
    swap(a[low],a[j]);
    return j;
}

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末麦向,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子客叉,更是在濱河造成了極大的恐慌诵竭,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兼搏,死亡現(xiàn)場離奇詭異卵慰,居然都是意外死亡,警方通過查閱死者的電腦和手機佛呻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門裳朋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吓著,你說我怎么就攤上這事鲤嫡。” “怎么了绑莺?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵暖眼,是天一觀的道長。 經(jīng)常有香客問我纺裁,道長诫肠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任欺缘,我火速辦了婚禮栋豫,結果婚禮上,老公的妹妹穿的比我還像新娘谚殊。我一直安慰自己笼才,他們只是感情好,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布络凿。 她就那樣靜靜地躺著骡送,像睡著了一般。 火紅的嫁衣襯著肌膚如雪絮记。 梳的紋絲不亂的頭發(fā)上摔踱,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天,我揣著相機與錄音怨愤,去河邊找鬼派敷。 笑死,一個胖子當著我的面吹牛撰洗,可吹牛的內(nèi)容都是我干的篮愉。 我是一名探鬼主播,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼差导,長吁一口氣:“原來是場噩夢啊……” “哼试躏!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起设褐,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤颠蕴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后助析,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體犀被,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡外冀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年寡键,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雪隧。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡西轩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出膀跌,到底是詐尸還是另有隱情遭商,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布捅伤,位于F島的核電站劫流,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏丛忆。R本人自食惡果不足惜祠汇,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望熄诡。 院中可真熱鬧可很,春花似錦、人聲如沸凰浮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至菜拓,卻和暖如春瓣窄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背纳鼎。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工俺夕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人贱鄙。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓劝贸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親逗宁。 傳聞我的和親對象是個殘疾皇子映九,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容