- (꒪ꇴ꒪ ),hello我是祐言
- 博客主页:C语言基础,Linux基础,软件配置领域博主🌍
- 快上🚘,一起学习!
- 送给读者的一句鸡汤🤔:
- 集中起来的意志可以击穿顽石!
- 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏
递归是编程中的一个重要概念,它允许函数调用自身以解决复杂的问题。在这篇博客中,我们将深入探讨C语言中的递归。我们将首先解释什么是递归,然后通过一些例子详细介绍如何在C语言中使用递归。
一、什么是递归?
递归是一种解决问题的方法,它将一个问题分解为更小的子问题,直到问题可以直接解决。使用递归的函数会自我调用,并且每次调用都会缩小问题的规模,这样直到可以直接计算结果。重要的是,每个递归调用都应该离解决问题更近一步,并且有一个清晰的终止条件。
二、如何在C语言中使用递归?
在C语言中,递归函数的定义和普通函数一样,只是它在函数体内部调用自己。以下是一个简单的递归函数的例子:
void recursiveFunction() {
... // some code
recursiveFunction(); // 调用它自己
... // some code
}
注意,这样的函数会无限地调用自己,因此我们需要设定一个终止条件。以下是一个更实际的例子,这个函数计算一个非负整数的阶乘:
unsigned long long factorial(unsigned int n) {
if (n == 0) {
return 1;
} else {
return n * factorial(n - 1);
}
}
三、递归的例子
让我们通过一些具体的例子来深入理解递归在C语言中的应用。
1.求1-100的和
递归求和是一个简单易懂的递归例子,以下是一个示例代码:
#include <stdio.h>
int sumn(int n) {
if (n == 1) {
return 1;
} else {
return n + sumn(n - 1);
}
}
int main() {
int n = 1000;
int result = sumn(n);
printf("从1到%d的和为:%d\n", n, result);
return 0;
}
我们 首先,在代码开头引入了stdio.h头文件,这是C语言中用于输入输出的标准库。
然后,定义了一个名为sumn的递归函数,该函数接受一个整数参数n,表示要计算的范围上限。
在函数内部,首先判断基本情况,即当n等于1时,直接返回1,表示从1到1的和为1。
如果n不等于1,就进行递归调用。递归调用的过程是将n减1,然后再调用sumn函数本身,传入减去1后的n。这样就将原问题转化为更小的子问题。
递归调用返回后,会得到子问题的解,即从1到n-1的和。然后将n与子问题的解相加,得到从1到n的和。
2.Fibonacci数列
Fibonacci数列是一个经典的递归问题。在这个数列中,每个数字是前两个数字的和。以下是一个递归函数来计算Fibonacci数列的第n项:
unsigned long long fibonacci(unsigned int n) {
if (n <= 1) { // base cases
return n;
} else {
return fibonacci(n - 1) + fibonacci(n - 2); // recursive case
}
}
3.汉诺塔问题
汉诺塔是另一个著名的递归问题。在这个问题中,我们有三根柱子和n个大小不同的盘子,开始时所有盘子按大小顺序堆在一根柱子上。我们的目标是将所有盘子移动到另一根柱子上,每次只能移动一个盘子,并且任何时候大盘子都不能在小盘子上面。以下是一个使用递归解决汉诺塔问题的函数:
void hanoiTower(int n, char from_rod, char to_rod, char aux_rod) {
if (n == 1) {
printf("\n 将盘子 1 从柱子 %c 移动到柱子 %c", from_rod, to_rod);
return;
}
hanoiTower(n - 1, from_rod, aux_rod, to_rod);
printf("\n 将盘子 %d 从柱子 %c 移动到柱子 %c", n, from_rod, to_rod);
hanoiTower(n - 1, aux_rod, to_rod, from_rod);
}
四、递归的优点和缺点
递归提供了一种强大而优雅的解决问题的方法,可以让我们以直观的方式解决复杂的问题。然而,递归也有其缺点。每次函数调用都会消耗一些内存和处理器时间。如果递归调用的层数太多,可能会导致栈溢出。此外,对于某些问题,非递归解决方案可能更有效。
1.优点
(1)代码简洁易读:递归的代码通常比使用循环的代码更简洁,更易于理解。递归的解决方案通常直接对应于问题的定义,因此更符合人的思维方式。
(2) 解决复杂问题:递归非常适合解决那些可以自然地分解为更小实例的问题,例如排序算法,搜索算法,动态规划等。
2.缺点
(1)空间和时间效率:递归函数由于需要反复调用自身,会产生大量的函数调用开销,可能引起栈溢出。每次函数调用都会在栈上创建一个新的环境以存储局部变量、返回地址等信息,如果递归调用的深度过大,会消耗大量的栈空间,甚至导致栈溢出。
(2)递归深度限制:大多数编程语言(包括C)都对递归深度有限制。如果递归调用深度超过这个限制,程序就会终止。
(3)可能引发复杂性:虽然递归在某些情况下可以简化问题,但在其他情况下,它可能会使问题变得更加复杂。理解和调试递归函数可能需要更多的思考和时间。
五、如何写出好的递归函数?
1.确定基本情况:基本情况是递归结束的条件,通常是问题的一个简单实例。在定义递归函数时,首先要确定基本情况。
2.确保你的函数在每次递归调用时都向基本情况靠近:你的函数应该在每次递归调用后,问题的规模都有所减小,以确保最终能达到基本情况。
3.通过测试验证你的函数:由于递归函数的复杂性,测试对于验证其正确性尤为重要。
六、总结
递归是编程中的一个强大工具,它能让我们以简洁和直观的方式解决复杂问题。然而,递归也有其复杂性和效率问题。作为一名优秀的程序员,理解何时以及如何使用递归是非常重要的。
附加小问题:
这是一道华为的笔试题,如果你能做出来,那么你对递归和指针的理解已经达到一定水平啦。
下面函数实现数组a元素的逆转,k为数组的元素个数。请填写空白处使其完整。
void recur(int a[], int k)
{
int tmp;
if( __ )
{
recur( __ , __ );
tmp = a[0];
a[0] = a[k-1];
a[k-1] = tmp;
}
}
答案在评论区!
更多C语言相关文章,关注专栏:
手撕C语言
📢写在最后
- 今天的分享就到这啦~
- 觉得博主写的还不错的烦劳
一键三连喔
~ - 🎉感谢关注🎉