算法设计与分析——2.1递归的概念


第二章递归与分治策略的学习流程如下:
在这里插入图片描述

分析问题、寻找递归关系:找出大规模问题与小规模问题的关系,这样通过递归使问题的规模逐渐变小。

设置边界、控制递归:找出停止条件,即算法可解的最小规模问题。

设计函数、确定参数:和其他算法一样设计函数体中的操作及相关参数。

2.1.1求阶乘

在这里插入图片描述
代码:

#include <iostream>
#include <cstring>
using namespace std;
int fun(int n)
{
    if(n==0) return 1;
    else return n*fun(n-1);
}

int main()
{
    int n;
    cin>>n;
    cout<<fun(n);
}

2.1.2二叉树叶子节点数

在这里插入图片描述
输入:ABD@F@@@CE@@@
代码:

#include <iostream>
#include <cstring>
using namespace std;
typedef struct tree
{
    char data;
    struct tree *lchild,*rchild;
}*NodeTree,BiTree;
NodeTree CreateTree()
{//递归中序建树
    NodeTree t;
    char c;
    scanf("%c",&c);
    if(c=='@')
        t=NULL;
    else
    {
        t=(NodeTree )malloc(sizeof(BiTree));
        t->data=c;
        t->lchild=CreateTree();
        t->rchild=CreateTree();
    }
    return t;
}
int CountLeaves(BiTree *t)
{
    if(t==NULL)//0片叶子
        return 0;
    else if(t->lchild==NULL&&t->rchild==NULL)
    //叶节点无左右儿子
        return 1;

    else//度数>0的结点进入递归,找到叶节点则累加
        return CountLeaves(t->lchild)+CountLeaves(t->rchild);
}
int main()
{
    NodeTree t;
    t=CreateTree();
    cout<<CountLeaves(t);
    return 0;
}


2.1.3Hanio塔

参考链接
(1)移动规则:
1.每次只能从一个柱子的最上面移动一个碟子到另外一个柱子上。
2.不能将大碟子放到小碟子的上面。
(2)分析问题:
假设A上面有N个盘子,如果我呢把N-1个盘子已经搬到了B上面,我只需要将A盘子放到这个C上面,第N个盘子的直径是最大的,再以后的搬动过程中是不需要动C上第N个盘子的。以上搬动N个盘子的问题,就变为搬N-1个盘子的问题。如此规则执行下去,只后只有一个圆盘的时候,问题直接解决了。

这种方式适合递归算法

 1 有递归出口,那就是当盘子只有一个时候,问题很简单,直接解决

  2 有策略能使问题规模缩小,并且问题是相似,

    a 将N-1个盘子从A 搬到B柱上面,(借助C)

    b 将A柱子上第N个盘子搬到C柱上面

    c 将B柱子上N-1个盘子搬到C柱子上面 (借助A)

在这里插入图片描述

#include <iostream>
#include <cstring>
using namespace std;
void Hanio(int n,int a,int b,int c)
{
    if(n==1)
    {
        printf("将第%d个盘子从%c移到%c上\n",n,a,c);
    }
    else
    {
        Hanio(n-1,a,c,b);//将前n-1个盘子从a借助c移到b
        printf("将第%d个盘子从%c移到%c上\n",n,a,c);
        Hanio(n-1,b,a,c);//将前n-1个从b借助a移到c

    }
}
int main()
{
    int n;
    printf("请输入要移动的块数:");
    cin>>n;
    Hanio(n,'A','B','C');
    return 0;
}
//3

输出:
在这里插入图片描述

2.1.4全排列

R = { r 1 , r 2 , … , r n } R=\{{r_1,r_2,…,r_n}\} R={r1,r2,,rn}是要进行排列的n个元素,求R的全排列 P e r m ( R ) Perm(R) Perm(R)。注:perm是permutation(排列的缩写)

例:{1,2,3}的全排列
从分治的角度考虑,可以划分为多个子问题,"1开头的全排列","2开头的全排列"...
当问题划分到单独数字的全排时无需划分,递归结束。
在这里插入图片描述
代码解释:
在这里插入图片描述

#include <iostream>
#include <cstring>
using namespace std;
void Swap(int &x,int &y)
{
    //交换a数组中的a[x]、a[y]
    int tmp = x;
    x = y;
    y = tmp;
}
void Perm(int a[],int k,int m)
{
    //k表示当前数字,m表示数字总数
    int i;
    if(k==m)//递归到最后一个数字输出
    {
        for(i=0; i<=m; i++)
            cout<<a[i]<<' ';
        cout<<endl;
    }
    else
    {
        for(i=k; i<=m; i++)
        {
            Swap(a[i],a[k]);//先和当前换
            Perm(a,k+1,m);//换完对下一个递归交换
            Swap(a[i],a[k]);
        }
    }
}
int main()
{
    int n,a[100];
    cin>>n;
    for(int i=0; i<n; i++)
    {
        cin>>a[i];
    }
    Perm(a,0,n-1);
    return 0;
}
//3

输出:
在这里插入图片描述

2.1.5瑞格习题:递归求最大值

在这里插入图片描述

#include <iostream>
#include <cstring>
using namespace std;
int getMax(int a[],int l,int r)
{
    int mid = (l+r)/2;
    int lmax,rmax;
    if(l==r) return a[l];
    else
    {
        lmax = getMax(a,l,mid);//对左边其最大
        rmax = getMax(a,mid+1,r);//对右边其最大
        return lmax>rmax?lmax:rmax;//取左右最大的
    }
}
int main()
{
    int n, a[100];
    cin>>n;
    for(int i= 0; i<n; i++)
    {
        cin>>a[i];
    }
    cout<<getMax(a,0,n-1);

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值