编程学习笔记8--递归的运用

递归的定义
在一个子程序(过程或函数)的定义中又直接或间接地调用该子程序本身,称为递归。递归是一种非常有用的程序设计方法。
递归调用的一般格式为:
if (边界条件1)
赋予边界值1
else if  (边界条件2)
赋予边界值2
 …… 
else
调用解决问题的通式  

递归解决问题的关键:1.找出递推公式2.找到递归终止条件
注意事项:由于函数的局部变量是存在栈上的,如果有体积大的局部变量,比如数组,而递归层次又可能很深的情况下,也许会导致栈溢出,因此可以考虑使用全局数组或动态分配数组

递归的形式

先操作 后遍历
void Func(char ch)
       {  if(ch<=‘z’)
           {  cout<<ch;
               Func(ch+1);
            }
       }

先遍历 后操作
void Func(char ch)
       {  if(ch<=‘z’)
           {  Func(ch+1);
               cout<<ch;}
       }



下面这些是我自己不会的,感谢提供代码的人,给我参考!

汉诺塔


河内之塔(Towers of Hanoi)是法国人M.Claus(Lucas)于1883年从泰国带至法国的,河内为越战时北越的首都,即现在的胡志明市; 1883年法国数学家 Edouard Lucas曾提及这个故事,据说创世纪时Benares有一座波罗教塔,是由三支钻石棒(Pag)所支撑,开始时神在第一根棒上放置64个由上至下依由小至大排列的金盘(Disc),并命令僧侣将所有的金盘从第一根石棒移至第三根石棒,且搬运过程中遵守大盘子在小盘子之下的原则,若每日仅搬一个盘子,则当盘子全数搬运完毕之时,此塔将毁损,而也就是世界末日来临之时。

#include <stdio.h>
void hanoi(int n, char A, char B, char C)
{
    if(n == 1)
    {
        printf("Move sheet %d from %c to %c\n", n, A, C);/**一个的时候直接放置*/
    }
    else
    {
        hanoi(n-1, A, C, B);/**移动第n个盘子的前提是先想办法把前面的n-1个盘子从A挪到B上,以C为辅助*/
        printf("Move sheet %d from %c to %c\n", n, A, C);/**完成后再把第n个从A移动到C上*/
        hanoi(n-1, B, A, C);/**最后把前n-1个盘子从B以A为辅助挪动到C上。
    }
}
int main()
{
    int n;
    printf("请输入盘数:");
    scanf("%d", &n);
    hanoi(n, 'A', 'B', 'C');
    return 0;
}

老鼠走迷官

老鼠走迷宫是递回求解的基本题型,我们在二维阵列中使用2表示迷宫墙壁,使用1来表示老鼠的行走路径,试以程式求出由入口至出口的路径。

解法老鼠的走法有上、左、下、右四个方向,在每前进一格之后就选一个方向前进,无法前进时退回选择下一个可前进方向,如此在阵列中依序测试四个方向,直到走到出口为止,这是递回的基本题,请直接看程式应就可以理解。

#include <stdio.h>
#include <stdlib.h>
int visit(int, int);
int maze[7][7] = {
                  {2, 2, 2, 2, 2, 2, 2},
                  {2, 0, 0, 0, 0, 0, 2},
                  {2, 0, 2, 0, 2, 0, 2},
                  {2, 0, 0, 2, 0, 2, 2},
                  {2, 2, 0, 2, 0, 2, 2},
                  {2, 0, 0, 0, 0, 0, 2},
                  {2, 2, 2, 2, 2, 2, 2}
                  };
int startI = 1, startJ = 1; // 入口
int endI = 5, endJ = 5; // 出口
int success = 0;
int main(void)
{
    int i, j;
    printf("显示迷宫:\n");
    for(i = 0; i < 7; i++)
    {
        for(j = 0; j < 7; j++)
        {
            if(maze[i][j] == 2)
                printf("█");
            else
                printf(" ");
        }
        printf("\n");
    }
    if(visit(startI, startJ) == 0)
    {
        printf("\n没有找到出口!\n");
    }
    else
    {
        printf("\n显示路径:\n");
        for(i = 0; i < 7; i++)
        {
            for(j = 0; j < 7; j++)
            {
                if(maze[i][j] == 2)
                    printf("█");
                else if(maze[i][j] == 1)
                    printf("◇");
                else
                    printf(" ");
            }
            printf("\n");
        }
    }
    return 0;
}
int visit(int i, int j)
{
    maze[i][j] = 1;
    if(i == endI && j == endJ)
        success = 1;
    if(success != 1 && maze[i][j+1] == 0) visit(i, j+1);
    if(success != 1 && maze[i+1][j] == 0) visit(i+1, j);
    if(success != 1 && maze[i][j-1] == 0) visit(i, j-1);
    if(success != 1 && maze[i-1][j] == 0) visit(i-1, j);
    if(success != 1)
    maze[i][j] = 0;
    return success;
}

八皇后



西洋棋中的皇后可以直线前进,吃掉遇到的所有棋子,如果棋盘上有八个皇后,则这八个皇后如何相安无事的放置在棋盘上,1970年与1971年, E.W.Dijkstra与N.Wirth曾经用这个问题来讲解程式设计之技巧。


关于棋盘的问题,都可以用递回求解,然而如何减少递回的次数?在八个皇后的问题中,不必要所有的格子都检查过,例如若某列检查过,该该列的其它格子就不用再检查了,这个方法称为分支修剪。

#include <stdio.h>
#include <stdlib.h>
#define N 8
int column[N+1]; // 同栏是否有皇后,1表示有
int rup[2*N+1]; // 右上至左下是否有皇后
int lup[2*N+1]; // 左上至右下是否有皇后
int queen[N+1] = {0};
int num; // 解答编号
void backtrack(int); // 递回求解
int main(void)
{
    int i;
    num = 0;
    for(i = 1; i <= N; i++)
        column[i] = 1;
    for(i = 1; i <= 2*N; i++)
    rup[i] = lup[i] = 1;
    backtrack(1);
    return 0;
}
void showAnswer()
{
    int x, y;
    printf("\n解答 %d\n", ++num);
    for(y = 1; y <= N; y++)
    {
        for(x = 1; x <= N; x++)
        {
            if(queen[y] == x)
            {
                printf(" Q");
            }
            else
            {
                printf(" .");
            }
        }
    printf("\n");
    }
}
void backtrack(int i)
{
    int j;
    if(i > N)
    {
        showAnswer();
    }
    else
    {
        for(j = 1; j <= N; j++)
        {
            if(column[j] == 1 &&rup[i+j] == 1 && lup[i-j+N] == 1)
            {
                queen[i] = j;// 设定为占用
                column[j] = rup[i+j] = lup[i-j+N] = 0;
                backtrack(i+1);
                column[j] = rup[i+j] = lup[i-j+N] = 1;
            }
        }
    }
}


















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值