今日思想:所谓万丈深渊,下去也是前程万里!
一、递归
1、递归的定义:大白话说就是函数自己调用自己
一个超简单的函数递归代码举例:
#include <stdio.h>
int main()
{
printf("hehe\n");
main();//main函数中⼜调⽤了main函数
return 0;
}
上图是一个很简单的代码,这个代码只是演示递归的基本形式,最终这个代码会死循环,直到栈溢出。
2、递归的思想:
递归就是把原来的问题化成一个个与原来的相似的子问题,通过层层化简直到子问题不能再化简,递归就结束。所以递归就是大事化小的过程。递就是递推,归就是回归。
二、递归的限制条件:
在写递归代码中有两个必要条件:
• 递归存在限制条件,当满足这个限制条件的时候,递归便不再继续。
• 每次递归调用之后越来越接近这个限制条件。
三、递归的举例
例子:求n的阶乘
公式:n*(n-1)!
题目分析:
1!=1
2!=1*2
3!=1*2*3
4!=1*2*3*4
5!=1*2*3*4*5
........
从这里可以看出:
5!=5*4!
4!=4*3!
3!=3*2!
........
无论是谁的阶乘他最终会回到1的阶乘(1!)
结论:当n=0时 阶乘为1
当n>0时 阶乘为n*(n-1)!
用一个函数来表示:
函数的实现:
#include<stdio,h>
int Fact(int n)
{
if(n==0)//递归的限制条件
{
return 1;
}
else
{
return n*Fact(n-1);
}
}
int main()
{
n=5;//求5的阶乘
int d=Fact(n);//阶乘的实现
printf("%d\n",d);
return 0;
}
图解:大家到这里还有些模糊,我画个图给大家应该就挺轻松理解的
注意:在递推过程中不会计算结果直到递推到限制条件然后回归的时候计算结果。
四、递归与迭代
像上面的Fact函数,当n的数字较大时,计算的过程中花费的时间较长例如100的阶乘,如果用Fact函数来算的话花费的时间较长。
在C语⾔中每⼀次函数调用,都需要为本次函数调⽤在内存的栈区,申请⼀块内存空间来保存函数调用期间的各种局部变量的值,这块空间被称为运行时堆栈,或者函数栈帧。 函数不返回,函数对应的栈帧空间就⼀直占用,所以如果函数调用中存在递归调用的话,每⼀次递归 函数调用都会开辟属于自己的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间。 所以如果采⽤函数递归的方式完成代码,递归层次太深,就会浪费太多的栈帧空间,也可能引起栈溢 出(stack overflow)的问题。
所以不用递归的方法,那就要思考其他方法,再次分析n的阶乘:
5!=5*4*3*2*1
这似乎可以用循环来解决
int d=1;
for(int n=1;n<=5;n++)
{
d=d*n;//d*=n;
}
这就是迭代的方法,据我理解就是不用递归的方法就是迭代的方法。
迭代大大提高了代码的运行速度、时间。