递归的本质·

        嗯,又抽了几天时间来写课程作业,,,

 

        今天复习的东西也是我当初学习的时候感觉到比较难的一个点——递归,这玩意我反正当初听老师讲的时候是挺抽象的,后面再来看的时候也还是花了一些精力来学习。

        首先我们要认识递归,递归这玩意是个啥?它不是一种算法,他仅仅是解决问题的一种思路,递归的代码都非常简洁,但是解决的问题都不简单,但是递归并不是最好用的一种思路,原因是它太耗费内存,并且它的效率并不高!为啥说它效率不高呢,这下我们就来谈谈递归的本质了。

        递归是一种思路,什么思路呢

        

当 n = 1时,f(1) = 1;

当 n = 2时,f(2) = 1;

当 n = 3时,f(3) = 1 + 1 = 2;

当 n = 4时,f(4) = 2 + 1 = 3;

当 n = 5时,f(5) = 3 + 2 = 5;
————————————————
大家都看得出上面是斐波那契数列,那么我要求其中的任意一个值,比如f(5),那么我们就只需要把f(5-2)+f(5-1),就行了。意思是不管求哪个值,我们都可以用这个数列里的其他值推导出来,那如果用函数来描述这个数列,那是不是求其中任意一个值的时候我们只需要重复使用该函数来求得这个值的前面两个值就ok了呢?是的,递归思想也即是这样,在函数里面重复调用自己的函数,这就是递归的思想。

        这么看还是挺抽象的,那先来讲讲如何构造递归,或者是构造递归所需要满足的条件是什么。

        一般我们在用递归思想来写代码的时候主要要明确三个点:

        1、你这个东西要用递归函数来写(函数函数函数!)

        2、明确递归函数的结束条件

        结束条件是什么东西?就是你的最初的值,递归递归,就是后面的东西可以根据前面的东西来推出来,那么总要有个东西你是要知道的,前面后面总要有个你是能够直接知道答案的,比如斐波那契数列需要根据前面两个的值推出后一个,那你就必须要有连续的两个值是知道的,比如第一个和第二个都是1,那么当n<=2的时候返回值都是1,这一步就叫找结束条件,一般来说找返回条件都是找n去极小值时候的解。

        3、找出递归函数的数学等式表达

        在这里面呢等式表达是需要一点数学功底的,但其实大部分的题目都会很明显的把数学表达式给你列出来,你对着看一般也能搞定。对着这三个条件来写的话,你是真会感觉写代码不难,但是递归的调用过程你对着代码来走反而不容易看出。

        我们先来根据这三点来写求解斐波那契数列

        

#include<stdio.h>
//第一步,明确你要写什么递归函数
/*
@n:求第几个斐波那契数
@f:求斐波那契数列中任意一个值的函数
@w:接受返回的值
返回值:
    返回斐波那契中第几个值
*/
int f(int n)
{
//接下来写结束条件
if(n<=2)
{
    return 1;
}
else
{
    //接下来写出这个题目的数学等式
    return  f(n-1)+f(n-2);
}
}
int main()
{
    int a;
    scanf("%d",&a);
    int w = f(a);
    printf("%d",w);
    return 0;
}
#include<stdio.h>
//写出这个函数干啥的
/*
@n:求谁的阶乘
@fac:求阶层的函数
返回值:
    返回一个数的阶乘
*/
int fac(int n)
{//写出结束条件
	if (n == 1)
        return 1;
//写出数学等式
	else
		return n * fac(n - 1);
}
int main()
{
	int n = 0;
	scanf("%d", &n);	
	printf("%d\n", fac(n));
	return 0;
}

        yysy,对着那三条规则来搞是不难的,但是阿写完之后让我久久不能理解的是程序在运行是的调用过程,这个阅读起来真的是很爆炸的,因为他是一层套一层的,但是呢递归又是疯狂的去调用自己,所以递归的代码看起来非常简洁,其实它展开是非常巨大的一个东西,这也是递归的一个确定,它是真的不方便阅读,阅读起来太麻烦了。

        那我们来彻底说说咋来搞这个递归代码,以上面的阶乘为例子阿

 

         上面我自己写了一个图示,从递归的字面意思我们也可以看出来一些东西,递归递归,先递后归,什么意思呢?:就是根据你写的等式条件一步步去接近你的结束条件,那么在此过程中会保留你的每一次调用所返回的值和函数,比如我上面那个图片,求3的阶乘阿,先根据我们写的函数可以知道,3不等于1,所以执行else,返回的是3*fac(3-1),这个会被储存,此时n = 3-1 = 2,接下来再判断,会发现2!=1,所以执行else,执行之后返回2*fac(2-1),这个时候 n = 1了,满足if里的条件,所以就返回1,这个时候调用就结束了!归:这个过程就简单了,一步步往回走,同时也是free的过程,要把之前储存的东西释放掉,所以到着走一边就回变成先1*2,把1的空间释放了,然后继续2*3,把2的空间释放了,最后就得到了3的阶乘就等于:1*2*3.

        上面我写的草稿还是不够严谨,把中间那一行改写成:

        3*f(3-1)-->2*f(2-1)

        这样会比较好

        通过这样来解释是不是就很好理解了,不仅仅让我对于递归函数这种方法的理解更加深刻了,同时还让我理解了前面学习在构造递归的时候,为什么结束条件要那样写,原来就是因为在往回走的时候走到最初的地方就不再调用函数了直接返回值,当递归函数没用调用本身的函数时候就说明递归已经结束了,进行不下去了,因为递归能一直运行的原因就是因为它可以调用自己(相当于一只狗追着自己尾巴咬)(这个好像就类似于循环里面的终止条件),而构造等式其实就是调用自己,这个是递归循环的动力(也像循环结构的循环体)

        到这里对于递归应该有了一个很清晰的认识了,再用上构造递归的三个要素,我觉得递归这一块应该是ok了,关于具体如何写,那当然还是多练习了,总而言之,递归代码是非常简洁,但是效率也是非常低,在递的过程天知道要开辟多少空间,浪费多少内存,所以在C里面感觉用的不多,重要的还是递归的思想。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值