如何去理解递归,想到递归,运用递归

递归:

首先要明白栈的知识,“后进先出”

递归的话是程序运行到某个点的时候,调用自身,这个时候,之前没运行完的程序会暂时不运行,等到下一层调用完了之后再运行。这个正是符合栈的先进后出。这个时候就会有个进栈,等到下一层调用完运行了,之后就可以出栈继续运行。

其次要明白运用递归需要的两个条件:

一、要有边界,也就是出口
二、有递推关系

最后记住用到递归的要领:

利用A函数实现功能时, A函数体需要用到同样的功能,这时候就要用到递归

上边糊涂吧,利用下边的例子,保证你就能明白怎么用递归,什么时候用递归!Go!


举例子理解:


例1.strlen递归解法

先找递推关系:
如果想char *s="abcdefg",求strlen(s):
步骤1:求strlen("bcdefg"),也就是strlen(s+1)
步骤2:将步骤1的结果加1返回即可
------------这就是递推关系,求s长度,需要求s+1长度 !!!
那边界条件呢:
当char *s=NULL或者char *s=‘\0’时,直接得到结果,而不用继续递归下去,这就是边界条件
分析好了,代码自然就出来了

int strlen(const char * s)
{
         //处理边界条件
          if(NULL==s)          
                    return -1;          
          else if('\0'==*s)
                     return 0;
          //递推关系 
          else 
                     return (strlen(s+1)+1);
}




例2:递归实现字符串逆序


比如:s=“abcdef”,逆序后变为“fedcba”

先找递推关系:
如果想逆序abcdef:
步骤1:将a和f进行交换
步骤2:对bcde进行逆序-------(需要同样的功能,所以必须用递归)
------------这就是递推关系,逆序“abcdef”,需要逆序“bcde”!!! 进一步可知,此递归函数得输入参数上标和下标

那边界条件呢?
当s里边无字符,也即为NULL情况下,不用排序
当s里边只有一个元素时,也不用排序,这就是边界条件

分析好了,代码自然就出来了:




char * Reverse_Str(char *s, int first ,int last)
{
        //边界条件:利用上标下标判定
        if(last<=first)
                   return s;
        else
          {
                       //交换首尾字符
                       char temp=s[first];
                       s[first]=s[last];
                       s[last]=temp;
                      //逆序中间部分
                       Reverse_Str(s,first+1,last+1);  //注意这里千万,不要first++,和last--,为什么,自己琢磨吧!
                        
          }
}



例3. 汉诺塔问题

 



先找递推关系:

               如果想n个盘子,先放在A,利用B,原样的放在C:

                                        步骤1:将A的最上方n-1个盘子,通过C,放在B中

                                        步骤2:将A的最上方那个盘子,通过B,放在C中

                                        步骤3:将B中那n-1个盘子,通过A,放在C中

------------这就是递推关系,函数的功能是,将A中的盘子,通过B,放在C中,而我们移动的每一个步骤,都是需要同样的功能。进一步得知,函数的参数,应该有A、B、C


    

那边界条件呢:

边界条件就是,只有一个盘子时,移动一次就够了。代码里表示,也就是输出,从哪移动到哪


分析好了,代码自然就出来了:


void hanoi(int n,char A,char B, char C)
{
           //边界条件
            if(1==n)
            {
                    printf("%c-------%c\n",A,C);
            }
            else
            {
                        hanoi(n-1,A,C,B);//步骤1
                        hanoi(1,A,B,C); //步骤2
                        hanoi(n-1,B,A,C);//步骤3
            }
}




例4:通用树遍历显示

先了解一下: 



文本的方式显示一颗树

A
---------B
----------------------E
----------------------F
---------C
---------D
----------------------H
----------------------I
----------------------J

A有子树节点B C D
B有子树节点E F
D有子树节点H I J



整个输出打印过程:
打印A结点
|
打印A结点的---孩子结点(具体:打印第一个孩子结点B,再打印B--的--孩子结点,接着同样的工作-打印孩子结点 C D.......)


单独拿出来,打印B孩子的结点分为:
打印B结点
|
打印B结点的孩子结点
对A,对B,打印执行的功能,是一样的

这就是一个递归!




先找递推关系:

                            

                                        步骤1:找到根节点,输出

                                        步骤2:找到孩子结点,输出

                                        

------------这就是递推关系,函数的功能是,先打印父结点,再打印孩子结点。而我们打印孩子结点时,需要同样的功能。

                     

static int recurse_display(GTreeNode * node,int format)
{
        int i;
        if(NULL!=node)
        {
           //1.打印根结点
               
            //1.1先打印占格符
           for(i=0;i<format;i++)
           {
               printf("%c",'-');


           }
           //1.2.打印父节点
           printf("%c",(int)(node->data));
           
           //1.3.换行
          printf("\n");
  
          //2.打印子节点     

           for(i=0;i<LinkList_Length(node->child);i++)
           {
                   //2.1获取子结点
                   TLNode* trnode=(TLNode*)LinkList_Get(node->child,i+1);
                     //2.2打印子节点的孩子结点
                   recurse_display(trnode->node,format+4);

           }

        }
}










例5. 求1+2+…+n


要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句(A?B:C)。
这道题递归一般的求解是:
先找递推关系:
如果想求1+2+.....+n:
步骤1:1+2+..+n-1
步骤2:n+步骤1的值
------------这就是递推关系,求值1+2++......+n,需要逆求1+2+.....+n-1 !!!
那边界条件呢?
当n小于等于0时,和为0
这就是边界条件




long getSumofN (int n)
{
         if(n<=0)
               return 0;
        else 
              return ( n+getSumofN(n-1) );
}



这里出现if else,不满足题意的,因此需要解决两个问题,如何判断边界条件,以及如何存储每次计算所得值
解决方法:执行---逻辑判断--语句



int getSumofN(int n, int *result)
{
        n&&getSumofN(n-1,result);    //前者用来判断边界,后者存储,执行步骤1
        return (*resulet +=n);   //执行步骤2
}


进一步给力:


int getSumofN(int n, int *result)
{

        return n&&getSumofN(n-1,result)&&(*resulet +=n);   //一步到位!变态
}




  • 10
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值