基本算法复习之递归:经典问题举例

来源:互联网 发布:淘宝可以不交保证金吗 编辑:程序博客网 时间:2024/05/18 21:43

递归程序要素:输入、出口条件、递归执行体、中间变量的存储以及返回值。

递归优劣:算法简洁明了,但是递归次数过多时可能导致堆栈溢出,而且不好的递归算法存在重复计算问题。

递归举例:

1.如下图,求从节点A到K的所有路径总数,路径只能从上往下,并且只能从某个节点到相距这个节点最近的下一行节点。
这里写图片描述

//line、clumn从1开始int pathsToNode(int line, int column){    if(line<=0 || column<=0 || column>line)        return 0;    if(column==1||column==line)        return 1;    return pathsToNode(line-1, column-1)+pathsToNode(line-1, column);}


2.翻牌问题

问题描述:
有52张扑克牌,使它们全部正面朝上。从第二张牌开始,把凡是2的倍数的位置上的牌翻成正面朝下:接着从第三张牌开始,把凡是3 的倍数位置上的正面朝上的牌翻成正面朝下,正面朝下的翻成正面朝上,接着从第四张牌开始,把凡是4的倍数位置上的牌按此规律翻转。依此类推,直到第1张要翻的是第52张牌为止。统计最后有几张牌正面朝上,并打印出它们的位置。

/*设牌正面朝上为0,反面朝上为1 n为第一张要翻的序号,2 <= n <= 52*/int cards[52];void turnOverCards(int n){    if(n>52)        return;    for(int i=n;i<53;i+=n)    {        if(cards[i-1])            cards[i-1]=0;        else            cards[i-1]=1;    }    turnOverCards(n+1);}int main(int argc, const char * argv[]){    for(int i=0;i<52;i++)        cards[i]=0;    turnOverCards(2);    printf("翻牌结束之后正面朝上的牌序号为:\n");    int count=0;    for(int i=0;i<52;i++)    {        if(!cards[i])        {            count++;            printf("%3d",i+1);        }    }    printf("\n总计%d张\n",count);    return 0;}


3.整数划分问题
问题描述:给定一个正整数n,将其分解为若干个正整数之和,即n = k1 + k2 + k3 + … kj + …,其中 n >= kj-1 >= kj > 0。

int partNK(int n, int k)    //n为待划分的整数,k为划分后的个整数中最大的那个,k可以是n本身                            //函数返回的是划分的种数    {      if(n < 1 || k < 1)            //不符合划分的定义          return 0;      if(n == 1 || k == 1)          //这种情况下只有一种,即1或1+1+1+⋯+1          return 1;      if(n < k)                     //根据定义,k不可能大于n          return p(n, n);                 if(n == k)                    //最大的加数先是n,然后是n-1,一直递归到1+1+⋯+1为止          return (p(n, k - 1) + 1);       return (p(n, k-1) + p(n-k, k));//返回划分种数}int partN(int n){      return partNK(n, n);}


4. m,n组合问题

问题描述:
给定两个正整数n和m,从数列1,2,3,…….n中随意去几个数,使其和等于m,要求将其中所有可能的组合列出来。

解法:
采用0-1背包的思想,把n看成n个背包,每个包装的东西“重量”为1,2,3,…,n,不装东西时重量为0。那么,原问题就转化成从这n个包里面选出若干个使其重量为m。考察某一个包,有两种情况:
(1)当选择n时,就用剩下的n-1填满 m-n;
(2)当不选择n时,就用剩下的n-1填满m。

上面的过程是一个递归的过程,出口:当m=n时,即找到了一个符合条件的解。

 int length;        //length就是n的值void printSolutions(int *flag){     for (int i=length-1; i>=0; i--)     {         if (flag[i] == 1)         {             printf("%d ",i+1);         }     }    printf("\n");}void BagProblem(int m, int n, int *flag){     if(n<1 || m<1)         return;     if(n>m)         n = m;     if (n == m)     {         flag[n-1] = 1;         printSolutions(flag);//输出结果,找到一种就输出一次         flag[n-1] = 0;       //输出之后立马清零,以免影响其他方案的输出     }    //若选择了n     flag[n-1] = 1;     putinBag(m-n, n-1, flag);    //若不选择n    flag[n-1] = 0;    outinBag(m, n-1, flag);}


5. 字符串全排列

void permutation_Iterate(char *s, char *begin){    if(*begin == '\0')    {        printf("%s\n",s);        return;    }    for(char *p = begin; *p != '\0'; p++)    {        char temp=*p;        *p = *begin;        *begin = temp;        permutation_Iterate(s, begin+1);        temp=*p;        *p = *begin;        *begin = temp;    }}void permuation(char *s){    if(s == NULL)        return;    permutation_Iterate(s, s);}


6. Fibonacci数列

递推式:F(n) = F(n-2) + F(n-1),n >= 2。F(0) = 0,F(1) = 1。

方法一:采用递归算法

int fib(n){    if(n <= 0)        return 0;    if(n==1)        return 1;    return fib(n-1) +fib(n-2);}


但是上面的方法每计算一次F(n)也会重新计算F(n-2)与F(n-1),共有(n-2)次冗余计算。下面是改进的方法,不用递归,而把F(n-2)与F(n-1)缓存起来以供后用。
方法二:

int fib2(unsigned int n){    if(n <= 0)        return 0;    if(n==1)        return 1;    int preFib2=0, preFib1=1, nowFib;    for(int i=0; i<n-1; i++)    {           nowFib=preFib2+preFib1;        preFib2=preFib1;        preFib1=nowFib;    }    return nowFib;}
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 韩博士装机卡在驱动恢复怎么办 xp打印后程序服务没有运行怎么办 刚注册的微信显示异常怎么办 不小心删了照片怎么办不要钱 qq邀请好友辅助验证成功后怎么办 微信申诉怎么让好友发验证码怎么办 微信申诉好友都删除了怎么办 恋与制作人原来的帐号不见了怎么办 手机号被别人注册了手机银行怎么办 想上老婆的陌陌号但要验证码怎么办 中国家医居民端注册信息有误怎么办 别人给我充的q币怎么办 qq忘记密码手机号码也换了怎么办 手机号码不用了微信忘记密码怎么办 手机号码注销了微信忘记密码怎么办 微信忘记密码手机号码也换了怎么办 微信钱包里的钱莫名少了怎么办 被骗给人冲q币了怎么办 支付宝账户异常无法领取红包怎么办 微信q币支付错了怎么办 王者荣耀不小心把点卷用了怎么办 微信绑定的qq号密码忘记了怎么办 微信红包实名认证没银行卡怎么办 手机烂了换新手机微信支付宝怎么办 支付宝转账给别人号码没用了怎么办 微信转账验证码收不到怎么办 陌生网友生日叫我发红包怎么办 微信群的群主不小心推出群该怎么办 支付宝验证码被别人知道了怎么办 微信解除银行卡绑定零钱清零怎么办 qq号被盗了理财通的钱怎么办 工行转错账号的钱被冻结怎么办 微信20w限额满了怎么办 通过qq号申请微信被盗了怎么办 微信号被盗手机绑定被改怎么办 腾讯视频激活码兑换达到限制怎么办 虚拟服务购买自动每月扣q币怎么办 微信被骗充值Q币怎么办 微信给别人充q币怎么办 k歌别人送的k币怎么办 忘记了qq号码但记得密码怎么办