1. 程式人生 > 其它 >資料結構-遞迴和分治

資料結構-遞迴和分治

斐波那契數 斐波那契數---遞迴實現 斐波那契數---迭代實現 遞迴實現逆序輸出 二分查詢(分治) 漢諾塔問題 八皇后問題(遞歸回溯實現) 目錄

遞迴和分治

斐波那契數

斐波那契數---遞迴實現

/*
    斐波那契數列 1 1 2 3 5 8 ...
    從第三個數開始每一個數都是前兩個數之和
    使用遞迴實現列印前40個斐波那契數

*/

# include<stdio.h>
# include<stdlib.h>

// 列印第i個斐波那契數
int fbnq(int n)
{
    if(n <= 2) return 1;
    else return fbnq(n - 1) + fbnq(n - 2);
}

int main()
{
    for(int i = 1 ; i <= 40 ; i ++) printf("%d ",fbnq(i));

    system("pause");
    return 0;
}

斐波那契數---迭代實現

/*
    斐波那契數列 1 1 2 3 5 8 ...
    從第三個數開始每一個數都是前兩個數之和
    使用迭代實現列印前40個斐波那契數(注意這個是使用陣列實現的)
*/
# include<stdio.h>
# include<stdlib.h>

int fbnqarr[1000];

int main()
{
    fbnqarr[0] = 1;
    fbnqarr[1] = 1;
    int fbnqn = 0;
    for(int i = 2 ; i < 40 ; i ++)
    {
        fbnqarr[i] = fbnqarr[i - 1] + fbnqarr[i - 2];
    }
    for(int i = 0 ; i < 40 ; i ++) printf("%d ",fbnqarr[i]);

    system("pause");
    return 0;
}

遞迴實現逆序輸出

/*
    使用遞迴實現輸入一個任意長度的字串,'#'表示結束輸入
    結束輸入之後將剛才的字串逆序輸出
*/

# include<stdio.h>
# include<stdlib.h>

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

int main()
{
    printf("請輸入字串!\n");
    nx_print();
    printf("\n");

    system("pause");
    return 0;
}

二分查詢(分治)

/*binary search
  二分查詢
    輸入一個數列長度n,表示將輸入一個長度為n的有序數列,接下來輸入有序數列
    輸入想要查詢的數字
    輸出查詢的數字的位置
*/

# include<stdio.h>
# include<stdlib.h>

const int MAXSIZE = 110;
// 1 2 3 4 4 6
// 二分查詢函式 傳入想要查詢的數字,順序數列,結果位置的指標,陣列的長度
void find(int x,int* arr,int *pos1,int *pos2,int n)
{
    int l = 0 , r = n - 1;
    
    while(l < r)
    {
        int mid = ( l + r ) / 2; // 注意每次mid都要更新,所以mid要寫在while內
        if(arr[mid] >= x) r = mid;
        else l = mid + 1;
    }
    if (x != arr[l]) *pos1 = -1, *pos2 = -1;
    else // 說明找到了左邊第一個為x的數,但是這裡還是有一種情況 1 2 3 4 4 5剛才只是找到了左邊的4,右邊的4的定位在使用一個二分(只是將check條件更改一下即可)
    {
        *pos1 = l;
        l = 0 , r = n - 1;
        
        while (l < r)
        {
            int mid = (l + r + 1) / 2;
            if( arr[mid] <= x) l = mid;
            else r = mid - 1;
        }
        *pos2 = l;
    }
}

int main()
{
    int n,e,findn;
    int arr[MAXSIZE];
    printf("輸入有序序列長度:\n");
    scanf("%d",&n);
    printf("依次輸入有序序列:\n");
    for(int i = 0 ; i < n ; i ++)
    {
        scanf("%d",&e);
        arr[i] = e;
    }
    printf("輸入想要查詢的數:\n");
    scanf("%d",&findn);

    int pos1 = -1 ,pos2 = -1;
    find(findn,arr,&pos1,&pos2,n);

    printf("想要查詢的數在有序序列中的順序依次為:");
    printf("%d %d\n",pos1 + 1,pos2 + 1);

    system("pause");
    return 0;
}

漢諾塔問題

漢諾塔核心:
1.將A柱上的n-1個移動到B柱上

2.將A柱上的第n個移動到C柱上

3.將B柱上的n-1個移動到C柱上(這裡就和1.2.開始遞迴就行)

/*
    漢諾塔問題
    有ABC三根柱子,A柱子上有個盤子
    要把A柱子上的盤子移動到C柱子上,在移動過程中可以藉助B柱子,但是要求小的盤子在上大的盤子在下。

    要求輸出入盤子的個數,輸出需要移動的次數。

   核心:
   漢諾塔分為以下核心三步:
   1.將A柱上n-1個移動到B柱上
   2.將A柱上第n個移動到C柱上
   3.將B柱上n-1個移動到C柱上(可以發現和第一步就相同了.....就這樣遞迴下去就可)
*/
# include<stdio.h>
# include<stdlib.h>

int cnt;
// hanoimove函式 傳入盤子的個數n,返回移動的次數
void hanoimove(int n,char a,char b,char c)  // 將a柱上的盤子(藉助b柱)移動到c柱上
{
    if( n == 1) 
    {
        // 移動A的最底下的一個盤子(這個整體中最大的盤子)通過B移動到C柱上
        cnt ++;
        printf("第%d次:將%c->%c上\n",cnt,a,c);
    }
    else
    {
        // 將A柱上N-1個盤子移動到B盤上
        hanoimove(n-1,a,c,b);
        cnt ++;
        printf("第%d次:將%c->%c上\n",cnt,a,c); 
        // 將B柱上的n-1個盤子移動到C柱上
        hanoimove(n-1,b,a,c);
    }

}

int main()
{
    int n;
    printf("請輸入A柱上盤子的個數:\n");
    scanf("%d",&n);

    char a = 'A',b = 'B', c = 'C';
    hanoimove(n,a,b,c);
    printf("一共移動了%d次\n",cnt);

    system("pause");
    return 0;
}

八皇后問題(遞歸回溯實現)

/*
    八皇后問題(英文:Eight queens),是由國際象棋棋手馬克斯·貝瑟爾於1848年提出的問題,是回溯演算法的典型案例。
    問題表述為:在8×8格的國際象棋上擺放8個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一
    斜線上,問有多少種擺法

    遞歸回溯方法:
    思路:
        0表示無,1表示這裡放置了一個皇后
        需要寫一個isdanger函式用來判斷該位置是否合法,find函式尋找下一個合法位置
        把第一行的第一個位置放上皇后,使用find函式去尋找下一個合法位置,合法就放上1,繼續find下一個合法位置,
    八行都填滿了(這個就是遞迴結束的條件),這時就找到了一種擺法。然後繼續去往第一行第二個位置放皇后繼續上述步驟..
*/

# include<stdio.h>
# include<stdlib.h>

int chess[8][8];
int cnt;

// 判斷位置是否合法,傳入位置(i,j)合法返回1,不合法返回0
// 即判斷這一行的哪個列位置是合法的
int isdanger(int i , int j)
{
    int f1 = 1, f2 = 1, f3 = 1, f4 = 1, f5 = 1;
    // 判斷這一列是否還有其他的皇后
    for(int row = 0; row < 8 ; row ++)
    {
        if(chess[row][j])
        {
            f1 = 0;
            break;
        }
    }
    // 判斷這個位置左上方是否有其他皇后
    for(int row = i ,col = j ; row >= 0 && col >= 0 ; row --,col --)
    {
        if(chess[row][col])
        {
            f2 = 0;
            break;
        }
    }
    // 判斷這個位置右上方是否有其他皇后
    for(int row = i,col = j ; row >= 0 && col < 8 ; row --,col ++)
    {
        if(chess[row][col])
        {
            f3 = 0;
            break;
        }
    }
    // 判斷這個位置左下方是否有其他皇后
    for(int row = i ,col = j ; row < 8 && col >= 0; row ++,col --)
    {
        if(chess[row][col])
        {
            f4 = 0;
            break;
        }
    }
    // 判斷這個位置右下方是否有其他皇后
    for(int row = i ,col = j; row < 8 && col < 8 ; row ++,col ++)
    {
        if(chess[row][col])
        {
            f5 = 0;
            break;
        }
    }

    return (f1 && f2 && f3 && f4 && f5);
}

// 實現八皇后位置的查詢與輸出
void eigthqueenfind(int row)
{
    if( row == 8 ) // row加到8就說明0-7 × 0-7 都已經完成了八皇后擺放
    {
        printf("第%d種\n", ++ cnt);
        // 結束條件
        for(int i = 0 ; i < 8 ; i ++)
        {
            for(int j = 0; j < 8 ; j ++)
            {
                printf("%d ",chess[i][j]);
            }
            printf("\n");
        }
        printf("\n");
    }
    else
    {
        for(int j = 0 ; j < 8 ; j ++) // 每一列都可以考慮到(由於這裡是for迴圈然後遞迴,所以可以遞歸回溯)
        {
            // printf("判斷(%d,%d)\n",row,j);
            if(isdanger(row,j))
            {
                // printf("判斷(%d,%d): 1\n",row,j);
                chess[row][j] = 1; // 如果找到了這一行的某個列位置是合法的就把皇后擺放上去
                eigthqueenfind(row + 1); // 這一行找到了就接著去尋找下一行
                chess[row][j] = 0; // 找到了,或者沒有找到都要將這個合法位置(row,j)重新設定成0,去尋找下一個
            }
        }
    } 
}
int main()
{
    eigthqueenfind(0);

    system("pause");
    return 0;
}
rds_blogs