
int
fun(int
n)
{
if(n=1)
return
1;
else
return
n+fun(n-1);
}
就是说前n项和可以分解为,n加上前n-1项和,而前n-1项和可以分解为n-1加上前n-2项和。如此循环。
即:sum
=
fun(100)=n+fun(100-1)=n+(n-1)+fun(n-2)
=n+(n-1)+(n-2)+fun(n-3)
=n+(n-1)+(n-2)+(n-3)++3+2+1;
类似这种可以这样分解的问题都可以用递归函数来实现。
比如:阶乘,等
public int getJiecheng(int n){
if(n==1){
return 1;
}else{
return getJiecheng(n)getJiecheng(n-1);
}
}
//写在某个类中调用函数的递归调用
递归问题是一个说简单也简单,说难也有点难理解的问题我想非常有必要对其做一个总结
首先理解一下递归的定义,递归就是直接或间接的调用自身而至于什么时候要用到递归,递归和非递归又有那些区别?又是一个不太容易掌握的问题,更难的是对于递归调用的理解下面我们就从程序+图形的角度对递归做一个全面的阐述
我们从常见到的递归问题开始:
1 阶层函数
#include <iostream>
using namespace std;
int factorial(int n)
{
if (n == 0)
{
return 1;
}
else
{
int result = factorial(n-1);
return n result;
}
}
int main()
{
int x = factorial(3);
cout << x << endl;
return 0;
}
这是一个递归求阶层函数的实现。很多朋友只是知道该这么实现的,也清楚它是通过不断的递归调用求出的结果但他们有些不清楚中间发生了些什么下面我们用图对此做一个清楚的流程:
根据上面这个图,大家可以很清楚的看出来这个函数的执行流程。我们的阶层函数factorial被调用了4次并且我们可以看出在调用后面的调用中,前面的调用并不退出。他们同时存在内存中。可见这是一件很浪费资源的事情。我们该次的参数是3如果我们传递10000呢。那结果就可想而知了肯定是溢出了就用int型来接收结果别说10000,100就会产生溢出即使不溢出我想那肯定也是见很浪费资源的事情我们可以做一个粗略的估计:每次函数调用就单变量所需的内存为:两个int型变量n和result在32位机器上占8B那么10000就需要10001次函数调用共需100018/1024 = 78KB这只是变量所需的内存空间其它的函数调用时函数入口地址等仍也需要占用内存空间。可见递归调用产生了一个不小的开销
2 斐波那契数列
int Fib(int n)
{
if (n <= 1)
{
return n;
}
else
{
return Fib(n-1) + Fib(n-2);
}
}
这个函数递归与上面的那个有些不同每次调用函数都会引起另外两次的调用最后将结果逐级返回
我们可以看出这个递归函数同样在调用后买的函数时,前面的不退出而是在等待后面的结果,最后求出总结果。这就是递归
3
#include <iostream>
using namespace std;
void recursiveFunction1(int num)
{
if (num < 5)
{
cout << num << endl;
recursiveFunction1(num+1);
}
}
void recursiveFunction2(int num)
{
if (num < 5)
{
recursiveFunction2(num+1);
cout << num << endl;
}
}
int main()
{
recursiveFunction1(0);
recursiveFunction2(0);
return 0;
}
运行结果:
0
1
2
3
4
4
3
2
1
0
该程序中有两个递归函数。传递同样的参数,但他们的输出结果刚好相反。理解这两个函数的调用过程可以很好的帮助我们理解递归:
我想能够把上面三个函数的递归调用过程理解了,你已经把递归调用理解的差不多了并且从上面的递归调用中我们可以总结出递归的一个规律:他是逐级的调用,而在函数结束的时候是从最后面往前反序的结束这种方式是很占用资源,也很费时的。但是有的时候使用递归写出来的程序很容易理解,很易读
为什么使用递归:
1 有时候使用递归写出来的程序很容易理解,很易读
2 有些问题只有递归能够解决非递归的方法无法实现如:汉诺塔
递归的条件:
并不是说所有的问题都可以使用递归解决,他必须的满足一定的条件。即有一个出口点也就是说当满足一定条件时,程序可以结束,从而完成递归调用,否则就陷入了无限的递归调用之中了并且这个条件还要是可达到的
递归有哪些优点:
易读,容易理解,代码一般比较短
递归有哪些缺点:
占用内存资源多,费时,效率低下
因此在我们写程序的时候不要轻易的使用递归,虽然他有他的优点,但是我们要在易读性和空间,效率上多做权衡一般情况下我们还是使用非递归的方法解决问题若一个算法非递归解法非常难于理解。我们使用递归也未尝不可如:二叉树的遍历算法非递归的算法很难与理解而相比递归算法就容易理解很多
对于递归调用的问题,我们在前一段时间写图形学程序时,其中有一个四连同填充算法就是使用递归的方法。结果当要填充的图形稍微大一些时,程序就自动关闭了这不是一个人的问题,所有人写出来的都是这个问题当时我们给与的解释就是堆栈溢出。就多次递归调用占用太多的内存资源致使堆栈溢出,程序没有内存资源执行下去,从而被 *** 作系统强制关闭了这是一个真真切切的例子。所以我们在使用递归的时候需要权衡再三函数用的是系统栈,栈的特点是先进后出
假设 str = "abcde";
递归函数当未达到末尾的'\0'时,就调用下一个字符的打印函数(这些就逐一保存在栈中,最先遍历到的在最底下,先遍历的总是在后遍历的下边)
到了str[i] == '\0' 的时候,不符合递归条件,就出栈,其实栈内保存的是print()函数和每个字符的地址,你可以想象一下,出栈的时候,从上到下,应该是"e d c b a"是吧,这样依次打印,顺序就自然而然逆序了首先这个代码有问题,void palin(n)应为void palin(int n)后面的int n;不要了,否则不能编译通过。
分析流程很简单:
假定输入34567
首先n=5;next=getchar()=3;
palin(n-1=4);next=getchar()=4(注意关键的地方,这个next和上一个next是不一样的,上一个next被压栈保护;)
……
palin(1);next=getchar()=7;(压栈完成,下面进行出栈)
putchar(next=7);7被pop出来;
……
弄清楚递归,一定要搞明白栈(first in last out)的结构,递归就是依赖栈运行的。在运行下一个递归函数前将上一个递归函数压栈,这个递归函数运行完成后,继续运行上一个递归函数;
这个递归如果拆开来写如下:
1 getchar() 输入3
2 getchar()输入4(上一个getchar()及得到的3被压栈)
3 getchar()……5
4 getchar()……6
5 getchar()……7
5 putchar() 输出7
4 putchar() 输出6
3 putchar() ………5
2 putchar()……4
1 putchar()……3
按照1234554321的次序,标号相同的语句是同一个函数的语句,正所谓first in last out 首先被执行getchar的最后被执行putchar
你要的公式:
=MIN(IF(A209^ROW($1:$99)<=5,ROW($1:$99),))
数组公式,同时按下Ctrl+Shift+Enter结束输入。
1、打开VC60软件,新建一个C语言的项目:
2、接下来编写主程序,首先定义用来求阶乘的递归函数以及主函数。在main函数里定义变量sum求和,调用递归函数fact(),并将返回值赋予sum,最后使用printf打印sum的结果,主程序就编写完了:
3、最后运行程序,观察输出的结果。以上就是C语言使用递归求阶乘的写法:
递归式解决逻辑问题的。基本思想是::把规模大的、较难解决的问题变成规模较小的、易解决的同一问题。规模较小的问题又变成规模更小的问题,并且小到一定程度可以直接得出它的解,从而得到原来问题的解。c有一个汉诺塔,就是非用递归才能解决的一个问题。
利用递归算法解题,首先要对问题的以下三个方面进行分析:
一、决定问题规模的参数。需要用递归算法解决的问题,其规模通常都是比较大的,在问题中决定规模大小(或问题复杂程度)的量有哪些?把它们找出来。
二、问题的边界条件及边界值。在什么情况下可以直接得出问题的解?这就是问题的边界条件及边界值。
三、解决问题的通式。把规模大的、较难解决的问题变成规模较小、易解决的同一问题,需要通过哪些步骤或等式来实现?这是解决递归问题的难点。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)