数据结构-递归和分治

递归和分治

斐波那契数

斐波那契数---递归实现

/*
    斐波那契数列 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;
}
posted @ 2021-10-28 20:09  r涤生  阅读(50)  评论(0编辑  收藏  举报