數據結構與算法之遞歸和分治思想

1、遞歸算法

      1.遞歸的定義函數

      一個過程或函數在其定義或說明中有直接或間接調用自身的一種方法叫作遞歸, 它一般把一個大型複雜的問題層層轉化爲一個與原問題類似的規模較小的問題來求解,遞歸策略只需少許的程序就可描述出解題過程所須要的屢次重複計算,大大地減小了程序的代碼量。遞歸的能力在於用有限的語句來定義對象的無限集合。spa

      通常來講,遞歸須要有邊界條件、遞歸前進段和遞歸返回段。當邊界條件不知足時,遞歸前進;當邊界條件知足時,遞歸返回。code

      使用遞歸要很是注意,不然會形成程序執行效率低。對象

      2.斐波那契數列blog

      若是說兔子在出生兩個月後,就有繁殖能力,一對兔子每月能勝出一對小兔子來。假設全部兔子都不會死去,可以一直繁殖下去,那麼一年之後能夠繁殖多少對兔子呢?遞歸

     

      (1)斐波那契數列的迭代實現內存

      咱們能夠用數學函數來定義:字符串

     

      代碼實現:打印出前40位斐波那契數列數,使用迭代實現數學

#include <stdio.h>

int main(){
    int i
    int a[40];

    a[0] = 0;
    a[1] = 1;
    printf("%d %d ", a[0], a[1]);

    for(i=2; i<40; i++){
        a[i] = a[i-1] + a[i-2];
        printf("%d ", a[i]);
    }
    return 0;
}

      (2)斐波那契數列的遞歸實現

int Fib(int i){
    if(i<2){
        return i == 0 ? 0 : 1;
    }
    return Fib(i-1) + Fib(i-2);
}

      (3)總結

  • 對比兩種實現方式,迭代和遞歸的區別是:迭代使用的是循環結構,遞歸使用的是選擇結構;
  • 使用遞歸能使程序的結構更清晰、更簡潔、更容易讓人理解,從而減小讀懂代碼的時間;
  • 可是大量的遞歸調用會建立函數的副本,會消耗大量的時間和內存,而迭代則不須要;
  • 遞歸函數分爲調用和回退階段,遞歸的回退順序是它調用順序的逆序。

      再舉個例子:計算n的階乘n!

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

      分析函數調用和回退順序:當n=5時

     

      3.實例分析

      題目:編寫一個遞歸函數,實現輸入的任意長度的字符串反向輸出的功能,例如輸入字符串LOVE,則輸出字符串EVOL;

      代碼實現:輸入結束條件爲"#"

void print(){
    char a;
    scanf("%c",  &a);
    if(a != '#'){
        print();
    }
    if(a != '#'){
        printf("%c", a);
    }
}

2、分治思想

      1.分治思想簡述

  • 當一個問題規模較大且不易求解的時候,就能夠考慮將問題分紅幾個小的模塊,再逐一解決;
  • 分治思想通常都會和遞歸一塊兒使用,由於採用分治思想處理問題,其各個小模塊一般具備與大問題相同的結構,這種特性也使遞歸技術有了用武之地。

      2.折半查找算法的遞歸實現

      折半查找法是一種經常使用的查找方法,該方法經過不斷縮小一半查找的範圍,直到達到目的,因此效率比較高。

      (1)迭代代碼實現

#include <stdio.h>

int bin_search( int str[], int n, int key )
{
        int low, high, mid;
        
        low = 0;
        high = n-1;

        while( low <= high ){
                mid = (low+high)/2;
                if( str[mid] == key ){
                        return mid;                // 查找成功
                }
                if( str[mid] < key ){
                        low = mid + 1;        // 在後半序列中查找
                }
                if( str[mid] > key ){
                        high = mid - 1;        // 在前半序列中查找
                }
        }

        return -1;                                // 查找失敗
}

int main()
{
        int str[11] = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89};
        int n, addr;

        printf("請輸入待查找的關鍵字: ");
        scanf("%d", &n);

        addr = bin_search(str, 11, n);
        if( -1 != addr ){
                printf("查找成功,可喜可賀,可口可樂! 關鍵字 %d 所在的位置是: %d\n", n, addr);
        }else{
                printf("查找失敗!\n");
        }

        return 0;
}

      (2)遞歸實現

#include <stdio.h>

int bin_search(int *str, int n, int key)
{
    int m, low = 0, high = n-1;
    int mid = (low+high)/2;

    if ( str [mid] == key)
        return mid;
    if ( str[low] >= str[high])
        return -1;
    if ( str[mid] < key ){ // 查找的key大於mid所在值
        low = mid + 1; // 將low移到原來mid的後一個位置
        m = bin_search(&str[low], high-low+1, key);
    }
    if ( str[mid] > key ){// 查找的key小於mid所在值
        high = mid - 1; // 將high移到原來mid的前一個位置
        m = bin_search(&str[low], high-low+1, key);
    }
    if ( -1 != m )
        m += low;

    return m;
}

int main(void)
{
    int str[11] = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89};
    int m,addr;

    printf("請輸入待查找的關鍵字: ");
    scanf("%d", &m);

    addr = bin_search(str, 11, m);
    if ( -1 != addr )
    {
        printf("查找成功,可喜可賀,可口可樂! 關鍵字 %d 所在的位置是: %d\n", m, addr);
    }
    else
    {
            printf("查找失敗!\n");
    }

    return 0;
}

 

本文爲原創文章,若是對你有一點點的幫助,別忘了點贊哦!比心!如需轉載,請註明出處,謝謝!

相關文章
相關標籤/搜索