6.C++函数递推递归
算法总结之递推与递归

算法总结之递推与递归递推算法递归算法⼤致包括两⽅⾯的内容:1)递归起点; 2)递归关系递推起点递归起点⼀般由题⽬或者实际情况确定,不由递归关系推出。
如果⽆法确定递归起点,那么递归算法就⽆法实现。
可见,递归起点是递归算法中的重要⼀笔。
递推关系递归关系是递归算法的核⼼。
常见的递归关系有以下⼏项:1)⼀阶递推;2)多阶递推;3)间接递推;4)逆向递推;5)多维递推。
下⾯通过栗⼦来详细介绍⼀下上述类别的递推关系。
1. ⼀阶递推在计算f(i)时,只⽤到前⾯项中的⼀项,如等差数列。
公差为3的等差数列,其递推关系为:f(i)=f(i-1)+3eg. 平⾯上10条直线最多能把平⾯分成⼏部分?分析:以直线数⽬为递推变量,假定i条直线把平⾯最多分成f(i)部分,则f(i-1)表⽰i-1条直线把平⾯分成的最多部分。
在i-1条直线的平⾯上增加直线i,易得i与平⾯上已经存在了的i-1条直线最多各有⼀个交点,即直线i最多被分成i段,⽽这i段将会依次将平⾯⼀分为⼆,即直线i将最多使平⾯多增加i部分。
所以,递推关系可表⽰为:f(i)=f(i-1)+i易得当0条直线时,平⾯为1部分。
所以f(0)=1为递推起点。
上述分析可⽤下⾯代码表⽰(c++):#define MAX 100int f[MAX] //存放f(i)int lines(int n){//输⼊n为直线数⽬//输出最多部分数int i;f(0)=1;for(i=1;i<=n;i++){f[i]=f[i-1]+3;}return f[i];}2. 多阶递推在计算f(i)时,要⽤到前⾯计算过的多项,如Fibonacci数列。
eg.求Fibonacci的第10项。
分析:总所周知,Fibonacci数列中的第n项等于第n-1项加上n-2项。
所以递推关系为f(i)=f(i-1)+f(i-2);且f[0]=f[1]=1。
C++代码如下:#define MAX 100int f[MAX];int fib(int n){//输⼊n为项数//输出第n个fib数int i;f[0]=0;f[1]=1;for(i=2;i<=n;i++){f[i]=f[i-1]+f[i-2];}return f[n]}3. 间接递推在计算f[i]时需要中间量,⽽计算中间量要⽤到之前计算过的项。
C++函数、递推、递归ppt课件

i = 7 s1 = 2 * (s2 + 1) ; s2 = s1 ;
// S(7) = 2 * (S(8) + 1) // s2 = s1 = S(7)
i = 6 s1 = 2 * (s2 + 1) ; s2 = s1 ;
// S(6) = 2 * (S(7) + 1) // s2 = s1 = S(6)
看一个简单的例子:
1 4
第九讲——函数、递推、递归
递归
有 5 个人坐在一起,问第 5 个人多少岁? 他说比第 4 个人 大两岁。问第 4 个人岁数,他说比第 3 个人大两岁。问第 3 个人,又说比第 2 个人大两岁。问第 2 个人,说比第 1 个人 大两岁。最后问第 1 个人,他说是 10 岁。请问第 5 个人多 大?
3
第九讲——函数、递推、递归
解题思路:
假设用 S(i) 表示第 i 天没吃之前的桃子数目;
则
S(1) 即为第 1 天所摘的桃子数; S(2) = S(1) * 1/2 – 1 第 2 天没吃之前的桃子数
S(3) = S(2) * 1/2 - 1 第 3 天没吃之前的桃子数
…
…
S(9) = S(8) * 1/2 - 1 第 9 天没吃之前的桃子数
= age(2) + 2 + 2 + 2 // c = age(2) + 2
= age(1) + 2 + 2 + 2 + 2;// c = 10;
2 2
计算年龄程序
第九讲——函数、递推、递归
2 3
第九讲——函数、递推、递归
递归算例(2)
用递归方法计算 n! 算法思路:
C语言中的递归函数应用

C语言中的递归函数应用递归函数在C语言中是一种非常重要且常用的编程技术,可以简化代码逻辑,实现程序的高效性和可维护性。
递归函数是指在函数中调用自身的函数,通过不断调用自身来解决问题,直到达到终止条件为止。
在C语言中,递归函数的应用非常广泛,比如在树的遍历、阶乘计算、斐波那契数列等方面都能看到递归函数的影子。
首先来看一个经典的递归函数示例,计算阶乘的函数:```cint factorial(int n) {if (n == 0) {return 1;} else {return n * factorial(n-1);}}```在上面的代码中,factorial函数通过调用自身来计算n的阶乘。
当n为0时,递归终止,返回1;否则,返回n与factorial(n-1)的乘积。
这种递归方式简洁而高效,使得代码更加易于理解。
另一个常见的应用是在树的遍历中,比如二叉树的先序、中序、后序遍历都可以通过递归函数实现。
以二叉树的中序遍历为例:```cvoid inorderTraversal(TreeNode* root) {if (root == NULL) {return;}inorderTraversal(root->left);printf("%d ", root->val);inorderTraversal(root->right);}```在上面的代码中,通过递归函数inorderTraversal实现了二叉树的中序遍历。
首先判断根节点是否为空,若为空则返回;否则,先递归遍历左子树,输出根节点的值,再递归遍历右子树。
这种递归方式简洁而直观,可以应用于各种树的遍历操作。
除此之外,递归函数还广泛应用于解决数学问题,比如求解斐波那契数列:```cint fibonacci(int n) {if (n == 0) {return 0;} else if (n == 1) {return 1;} else {return fibonacci(n-1) + fibonacci(n-2);}}```在上面的代码中,通过递归函数fibonacci实现了斐波那契数列的计算。
c 递归算法

c 递归算法
C语言中,递归是一种算法设计方法,它允许函数在自身调用中进行迭代。
通过将一个大问题分解为一个或多个规模较小的子问题,递归可以解决复杂的问题。
递归算法有以下主要特点:
1. 基本情况(Base Case):递归算法必须有一个或多个基本情况,也称为递归终止条件。
当达到基本情况时,递归将停止并返回结果,避免无限循环。
2. 递归调用:递归算法通过在函数内部调用自身来解决问题的规模更小的子问题。
每次递归调用都将原问题分解为规模较小的子问题,直到达到基本情况。
递归算法可以解决一些问题,但需要注意以下几点:
- 确保递归能够收敛到基本情况,避免无限递归导致栈溢出。
- 递归算法的执行效率可能较低,因为每次递归调用都会产生函数调用开销和栈空间的使用。
- 在设计递归算法时,需要合理选择递归终止条件和递归调用,以确保正确性和高效性。
以上是关于C语言中递归算法的一些基本概念和示例,希望对你有帮助。
c语言中的递归 (1)

c语言中的递归递归是一种常见的编程技巧,也是C语言中的重要概念之一。
通过递归,我们可以将一个复杂的问题分解成更小的子问题,从而简化解决方案。
在C语言中,递归函数是一种自己调用自己的函数,它可以通过不断调用自身来解决问题。
递归函数通常包含两个部分:基本情况和递归情况。
基本情况是指递归函数停止调用自身的条件,而递归情况则是指递归函数调用自身的情况。
在编写递归函数时,我们需要确保递归情况最终会达到基本情况,否则递归函数将陷入无限循环。
一个经典的例子是计算阶乘。
阶乘是指从1到某个正整数n的所有整数的乘积。
我们可以使用递归函数来计算阶乘。
首先,我们需要定义基本情况,即当n等于1时,阶乘的结果为1。
然后,我们定义递归情况,即当n大于1时,阶乘的结果为n乘以(n-1)的阶乘。
下面是一个使用递归函数计算阶乘的示例代码:```c#include <stdio.h>int factorial(int n) {if (n == 1) {return 1;} else {return n * factorial(n - 1);}}int main() {int n;printf("请输入一个正整数:");scanf("%d", &n);printf("%d的阶乘是%d\n", n, factorial(n));return 0;}```在上面的代码中,我们定义了一个名为factorial的递归函数,它接受一个整数n作为参数,并返回n的阶乘。
在递归情况中,我们调用了自身,并将n减1作为参数传递给递归函数。
当n等于1时,递归函数将返回1,从而达到基本情况。
递归函数的执行过程可以用一棵树来表示,这棵树被称为递归树。
每个节点表示一个函数调用,树的根节点表示初始函数调用,叶子节点表示基本情况。
通过递归树,我们可以更好地理解递归函数的执行过程。
然而,递归并不是解决所有问题的最佳方法。
C语言递归详细解答

C语言递归详细解答.txt喜欢我这是革命需要,知道不?!你不会叠衣服一边呆着去!以后我来叠!我一定要给你幸福,谁也别想拦着。
递归递归是设计和描述算法的一种有力的工具,由于它在复杂算法的描述中被经常采用,为此在进一步介绍其他算法设计方法之前先讨论它。
能采用递归描述的算法通常有这样的特征:为求解规模为N的问题,设法将它分解成规模较小的问题,然后从这些小问题的解方便地构造出大问题的解,并且这些规模较小的问题也能采用同样的分解和综合方法,分解成规模更小的问题,并从这些更小问题的解构造出规模较大问题的解。
特别地,当规模N=1时,能直接得解。
【问题】编写计算斐波那契(Fibonacci)数列的第n项函数fib(n)。
斐波那契数列为:0、1、1、2、3、……,即:fib(0)=0;fib(1)=1;fib(n)=fib(n-1)+fib(n-2) (当n>1时)。
写成递归函数有:int fib(int n){ if (n==0) return 0;if (n==1) return 1;if (n>1) return fib(n-1)+fib(n-2);}递归算法的执行过程分递推和回归两个阶段。
在递推阶段,把较复杂的问题(规模为n)的求解推到比原问题简单一些的问题(规模小于n)的求解。
例如上例中,求解fib(n),把它推到求解fib(n-1)和fib(n-2)。
也就是说,为计算fib(n),必须先计算fib(n-1)和fib(n-2),而计算fib(n-1)和fib(n-2),又必须先计算fib(n-3)和fib(n-4)。
依次类推,直至计算fib(1)和fib(0),分别能立即得到结果1和0。
在递推阶段,必须要有终止递归的情况。
例如在函数fib中,当n为1和0的情况。
在回归阶段,当获得最简单情况的解后,逐级返回,依次得到稍复杂问题的解,例如得到fib(1)和fib(0)后,返回得到fib(2)的结果,……,在得到了fib(n-1)和fib(n-2)的结果后,返回得到fib(n)的结果。
c语言使用递归函数

递归函数是一种特殊的函数,它调用自身来解决问题。
在C语言中,递归函数可以通过以下方式实现:
1. 定义一个函数,该函数返回一个值,或者没有返回值(void)。
2. 在函数的函数体中,使用return语句或break语句来结束函数的执行。
3. 在函数的函数体中,调用自身,将问题的规模减小,直到问题能够直接解决为止。
下面是一个简单的递归函数示例,该函数计算一个数的阶乘:
```c
#include <stdio.h>
int factorial(int n) {
if (n == 0) {
return 1;
} else {
return n * factorial(n - 1);
}
}
int main() {
int n = 5;
int result = factorial(n);
printf("%d! = %d\n", n, result);
return 0;
}
```
在上面的代码中,factorial()函数是一个递归函数。
当n等于0时,函数返回1。
否则,函数返回n乘以factorial(n-1)的结果。
在main()函数中,我们调用factorial()函数来计算5的阶乘,并将结果打印到控制台上。
C语言中的递归函数如何实现?

C语言中的递归函数如何实现?在 C 语言的世界里,递归函数是一种强大而又神秘的工具。
它就像是一把双刃剑,用得好可以让程序简洁高效,用不好则可能让程序陷入无限的循环和错误之中。
那么,究竟什么是递归函数,又该如何实现它呢?首先,我们来理解一下递归函数的概念。
简单来说,递归函数就是一个在函数内部调用自身的函数。
这听起来可能有点绕,但其实举个例子就很好理解。
比如计算阶乘,阶乘的定义是 n 的阶乘等于 n 乘以(n 1) 的阶乘,当 n 为 0 或 1 时,阶乘为 1。
我们可以用递归函数来实现计算阶乘的功能:```cinclude <stdioh>int factorial(int n) {if (n == 0 || n == 1) {return 1;} else {return n factorial(n 1);}}int main(){int num = 5;int result = factorial(num);printf("%d 的阶乘为%d\n", num, result);return 0;}```在这个例子中,`factorial` 函数就是一个递归函数。
当`n` 为 0 或1 时,函数直接返回 1,这就是递归的终止条件。
否则,它就通过`n factorial(n 1)`来调用自身,不断地将问题规模缩小,直到达到终止条件。
实现递归函数,有两个关键的要点。
一是要有明确的终止条件。
就像上面的阶乘例子,如果没有终止条件,函数就会一直调用自身,永无止境,最终导致栈溢出错误。
终止条件是递归能够正确结束的保障,它让函数在适当的时候停止递归调用,返回结果。
二是要能够将问题逐步分解为更小的、相似的子问题。
还是以阶乘为例,计算 n 的阶乘,就可以分解为计算(n 1) 的阶乘,然后再乘以n。
通过不断地分解问题,最终达到终止条件,从而得到结果。
再来看一个经典的例子——斐波那契数列。
斐波那契数列的定义是前两个数为 0 和 1,从第三个数开始,每个数都是前两个数之和。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
例6.4 定义一个函数check(n,d),让它返回一个布尔值。如果数字d在正整数n的 某位中出现则送回true,否则送回false。 例如:check(325719,3)==true;check(77829,1)==false;
例6.1 求:1!+2!+3!+„„+10!
#include<iostream> using namespace std; int main() { int sum=0; for (int i=1; i<=10; i++) sum+=js(i); cout<<"sum="<<sum<<endl; return 0; }
第六章 函数和递推递归算法
第一节 函数 第二节 递推算法 第三节 递归算法
前面我们曾经学习了程序设计中的三种基本控制结构(顺序、分 支、循环)。用它们可以组成任何程序。但在应用中,还经常用到子 程序结构。 通常,在程序设计中,我们会发现一些程序段在程序的不同地方 反复出现,此时可以将这些程序段作为相对独立的整体,用一个标识 符给它起一个名字,凡是程序中出现该程序段的地方,只要简单地写 上其标识符即可。这样的程序段,我们称之为子程序。 子程序的使用不仅缩短了程序,节省了内存空间及减少了程序的 编译时间,而且有利于结构化程序设计。因为一个复杂的问题总可将 其分解成若干个子问题来解决,如果子问题依然很复杂,还可以将它 继续分解,直到每个子问题都是一个具有独立任务的模块。这样编制 的程序结构清晰,逻辑关系明确,无论是编写、阅读、调试还是修改, 都会带来极大的好处。 在一个程序中可以只有主程序而没有子程序(本章以前都是如此), 但不能没有主程序,也就是说不能单独执行子程序。 在此之前,我们曾经介绍并使用了C++提供的各种标准函数,如 abs(),sqrt()等等,这些系统提供的函数为我们编写程序提供了很大 的方便。比如:求sin(1)+ sin(2)+...+sin(100)的值。但这些函 数只是常用的基本函数,编程时经常需要自定义一些函数。
在此例中,因为swap函数的参数为引用参数,所以,在函数swap中修 改a,b的值相当于在主函数main中修改c,d的值。
3.const形参 使用const修饰参数可避免在函数执行中修改参数。 举个例子:
void solve(const int &a) { a=1; } //该函数是错误的,因为a是 const形参,所以在函数体中不能被修改。
double area(double a,double b,double c) //此函数为 海伦-秦九韶公式 { double p=(a+b+c)/2; return sqrt(p*(p-a)*(p-b)*(p-c)); }
在函数说明中,如果形参的个数不止 一个,那么在程序中调用函数的实参个数 一定要与形参的个数一致,第一个实参对 应第一个形参,第二个实参对应第二个形 参...次序不能对调。
例6.3 任意输入10组三角形的三边,求其面积。 我们可以定义一个已知三角形三边求其面积的函数,设为area(a,b,c)。 程序如下:
#include<iostream> #include<cmath> using namespace std; double area(double,double,double); int main() { for (int i=1; i<=10; ++i) { double a,b,c; cout<<"input a,b,c"<<endl; cin>>a>>b>>c; if ((a+b<=c)||(a+c<=b)||(b+c<=a)) cout<<"data error!"<<endl; //判断三角形是否合法 else cout<<"s="<<area(a,b,c)<<endl; } return 0; }
使用const修饰参数也可使函数接受常量作为引用参数。 举个例子:
void fa(const int &a) { } void fb(int &a) { } int main() { fa(2); //正确,因为fa()使用了常量引用形参。 fb(2); //错误,因为fb()使用了非常量引用形参,不可以接受常量2。 }
1.函数的声明 调用函数之前先要声明函数原型。在主调函数中,或所有函数定义 之前,按如下形式声明: 类型说明符 被调函数名(含类型说明的形参表); 如果是在所有函数定义之前声明了函数原型,那么该函数原型在本 程序文件中任何地方都有效,也就是说在本程序文件中任何地方都可以 依照该原型调用相应的函数。如果是在某个主调函数内部声明了被调用 函数原型,那么该原型就只能在这个函数内部有效。 函数原型和函数定义在返回值类型、函数名和参数个数与类型必须 完全一致,否则,就会发生编译错误。下面对max()函数原型声明是合法 的。 int max(int x, int y); 也可以: int max(int , int ); 可以看到函数原型声明与函数定义时的第一行类似,只多了一个分 号,成为了一个声明语句而已。
现在的问题是:C++不提供js(x)这样一个标准函数,这个程序是 通不过的。如果是C++的标准函数,我们可以直接调用,如abs(x), sqrt(x)......而C++提供给我们的可供直接调用的标准函数不 多。没关系,我们编写自己的函数!
1.函数定义的语法形式
数据类型 函数名(形式参数表) { 函数体 //执行语句 } 关于函数的定义有如下说明: 函数的数据类型是函数的返回值类型(若数据类型为 void ,则无返回 值)。 函数名是标识符,一个程序中除了主函数名必须为main外,其余函数的 名字按照标识符的取名规则可以任意选取,最好取有助于记忆的名字。 形式参数(简称形参)表可以是空的(即无参函数);也可以有多个形 参,形参间用逗号隔开,不管有无参数,函数名后的圆括号都必须有。 形参必须有类型说明,形参可以是变量名、数组名或指针名,它的作 用是实现主调函数与被调函数之间的关系,通常将函数所处理的
编写一个阶乘的函数,我们给此函数取一个名字js。
int js(int n) { int s=1; for (int i=1; i<=n; ++i) s*=i; return s; }
在本例中,函数名叫js,只有一个int型的自变量n,函数js属 int型。在本函数中,要用到两个变量i,s。在函数体中,是一个求 阶乘的语句,n的阶乘的值在s中,最后由return语句将计算结果s值 带回,js()函数执行结束,在主函数中js()值就是s的值。 在这里,函数的参数n是一个接口参数,说得更明确点是入口参 数。如果我们调用函数:js(3),那么在程序里所有有n的地方,n被 替代成3来计算。在这里,3就被称为实参。又如:sqrt(4),ln(5), 这里4,5叫实参。而ln(x),sqrt(x)中的x,y叫形参。
数据、影响函数功能的因素或者函数处理的结果作为形参。在被调用 函数中的参数被称为形参。 函数中最外层一对花括号“{ }”括起来的若干个说明语句和执行语句 组成了一个函数的函数体。由函数体内的语句决定该函数功能。函数 体实际上是一个复合语句,它可以没有任何类型说明,而只有语句, 也可以两者都没有,即空函数。 函数不允许嵌套定义。在一个函数内定义另一个函数是非法的。但是 允许嵌套使用。 函数在没有被调用的时候是静止的,此时的形参只是一个符号,它标 志着在形参出现的位置应该有一个什么类型的数据。函数在被调用时 才执行,也就是在被调用时才由主调函数将实际参数(简称实参)值 赋予形参。这与数学中的函数概念相似,如数学函数: f(x)= x 2+x+1
1.非引用参数 普通的非引用类型的参数是通过复制对应的实参实现初始化。当 用参数副本初始化形参时,函数并没有访问调用所传递的实参本身, 因此不会修改实参的值。举个例子:
#include<iostream> using namespace std; void swap(int a,int b) { int tmp=a;a=b;b=tmp; } int main() { int c=1,d=2; swap(c,d); cout<<c<<' '<<d<<endl; return 0; } //程序输出为:1 2
例6.2 求1!+2!+„„+10!的值。 程序如下:
#include<iostream> using namespace std; nt js(int); int main() { int sum=0; for (int i=1; i<=10; ++i) sum+=js(i); cout<<"sum="<<sum<<endl; return 0; } int js(int n) { int s=1; for (int i=1; i<=n; ++i) s*=i; return s; }
这样的函数只有当自变量被赋值以后,才能计算出函数的值。
2.函数定义的例子 定义一个函数,返回两个数中的较大数。
int max(int x,int y) { return x>y?x:y; }
该函数返回值是整型,有两个整型的形参,用来接受实参传递的 两个数据,函数体内的语句是求两个数中的较大者并将其返回主调函 数。