數(shù)據(jù)結(jié)構(gòu)與算法9-遞歸

遞歸方法就是直接或者間接的調(diào)用自己,它可以將一些發(fā)雜問題簡化。

遞歸在下列方法中經(jīng)常會(huì)用到:

  • 定義是遞歸的。

如斐波拉契數(shù)列、階乘等。

  • 數(shù)據(jù)結(jié)構(gòu)是遞歸的。

數(shù)據(jù)結(jié)構(gòu)本身具有遞歸性,如鏈表、樹等。

  • 問題的解法是遞歸的。

有一類問題,雖然問題本身沒有明顯的遞歸結(jié)構(gòu),但采用遞歸求解比迭代求解更簡單。如漢諾塔問題、八皇后問題、迷宮問題。

所有的遞歸都能用循環(huán)解決

分治法

在求解4!時(shí),我們會(huì)先求解3!,然后再進(jìn)一步分解進(jìn)行求解,這種求解叫做分治法

使用分治法需要滿足3個(gè)條件:

  • 能將一個(gè)問題轉(zhuǎn)換成一個(gè)小問題,新問題和原問題的解法相同或類同。不同的只是被處理的對(duì)象,并且這些處理更小且變化是有規(guī)律的。
  • 可以通過上述轉(zhuǎn)換而使得問題簡化。
  • 必須有一個(gè)明確的遞歸出口,或成為遞歸邊界。
漢諾塔問題

在經(jīng)典漢諾塔問題中,有 3 根柱子及 N 個(gè)不同大小的穿孔圓盤,盤子可以滑入任意一根柱子。一開始,所有盤子自上而下按升序依次套在第一根柱子上(即每一個(gè)盤子只能放在更大的盤子上面)。

移動(dòng)圓盤時(shí)受到以下限制:

  • 每次只能移動(dòng)一個(gè)盤子;
  • 盤子只能從柱子頂端滑出移到下一根柱子;
  • 盤子只能疊在比它大的盤子上。

解決思路
我們使用遞歸來解決:

  • n=1時(shí),直接把盤子從A移動(dòng)到C就行了。(遞歸邊界)
  • n>1時(shí):
    • 先把n-1個(gè)盤子從A移動(dòng)到B;(子問題,遞歸)
    • 將最大的盤子從A移動(dòng)到C;
    • 再將B上n-1個(gè)盤子移動(dòng)到C。(子問題,遞歸)
用棧解決
static void move(LinkStack *A, LinkStack *B, LinkStack *C, int n) {
    if (n == 1) {
        int elem;
        Pop(A, &elem);
        Push(C, elem);
    } else {
          // 把棧A中n-1個(gè)盤子放到棧B
        move(A, C, B, n - 1);
        // A棧出棧放入C棧
        int elem;
        Pop(A, &elem);
        Push(C, elem);
          // 把棧B中n-1個(gè)盤子放到棧C
        move(B, A, C, n - 1);
    }
}

void hanoi(LinkStack *A, LinkStack *B, LinkStack *C) {
    move(A, B, C, StackLength(*A));
}

int main(int argc, const char * argv[]) {
    int n = 5;
    LinkStack A, B, C;
    InitStack(&A);
    InitStack(&B);
    InitStack(&C);
    for (int i = n; i > 0; i--) {
        Push(&A, i);
    }
    printf("原始棧A:");
    StackTraverse(A);
    printf("原始棧C:");
    StackTraverse(C);
    
    hanoi(&A, &B, &C);
    
    printf("移動(dòng)后棧A:");
    StackTraverse(A);
    printf("移動(dòng)后棧C:");
    StackTraverse(C);
    
    return 0;
}
// 輸出
原始棧A:1 2 3 4 5 
原始棧C:
移動(dòng)后棧A:
移動(dòng)后棧C:1 2 3 4 5 
移動(dòng)過程
void hanoi2(char *A, char *B, char *C, int n) {
    if (n == 1) {
        printf("move %s to %s\n", A, C);
    } else {
        hanoi2(A, C, B, n - 1);
        printf("move %s to %s\n", A, C);
        hanoi2(B, A, C, n - 1);
    }
}
int main(int argc, const char * argv[]) {
    hanoi2("a", "b", "c", 3);
    return 0;
}
// 輸出
move a to c
move a to b
move c to b
move a to c
move b to a
move b to c
move a to c
image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容