对于C语言函数递归的简单理解(新手入门必看!!!)

news/2024/7/1 8:12:06

什么是函数递归?

程序调用自身的编程技巧称为递归(recursion)。
递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接
调用自身的 一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略:
只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归的主要思考方式在于:把大事化小
递归顾名思义也可以这样理解:递送与回归。
这里引用站上一位大佬的话:
我觉得特别贴切
“递归:你打开面前这扇门,看到屋里面还有一扇门。你走过去,发现手中的钥匙还可以打开它,你推开门,发现里面还有一扇门,你继续打开它。若干次之后,你打开面前的门后,发现只有一间屋子,没有门了。然后,你开始原路返回,每走回一间屋子,你数一次,走到入口的时候,你可以回答出你到底用这你把钥匙打开了几扇门。

   循环:你打开面前这扇门,看到屋里面还有一扇门。你走过去,发现手中的钥匙还可以打开它,你推开门,发现里面还有一扇门(若前面两扇门都一样,那么这扇门和前两扇门也一样;如果第二扇门比第一扇门小,那么这扇门也比第二扇门小,你继续打开这扇门,一直这样继续下去直到打开所有的门。但是,入口处的人始终等不到你回去告诉他答案。”

再放一个通俗易懂的列子,帮助大家更好的理解递归:

我需要打开快递包装,于是买了个剪刀。但是剪刀也有包装,所以我又买了一个剪刀,这个剪刀上又有包装,所以我又买了个剪刀。。。
最后我没钱了,于是我用牙撕开了最后一个剪刀的包装,然后用这个剪刀打开了倒数第二个简单的包装,然后。。。最后用第一个剪刀打开了快递的包装,拿出了东西。
这个沙雕的过程就叫递归,递归必须要有停止条件(例子中是我把钱花完),要不然你就会拥有无数的剪刀,但又打不开快递(忘了目的系列)。
 

下面放几个简单的程序来进行递归的理解与使用。
1.接受一个整型值(无符号),按照顺序打印它的每一位。
void print(unsigned int n) // n=1234
{if (n > 9){print(n / 10); //123 12 1}printf("%d ", n % 10); 1 2 3 4
}int main()
{unsigned int num = 0;scanf("%u", &num);print(num);return 0;
}

2.编写函数不允许创建临时变量,求字符串的长度。

int my_strlen(char* s)
{if (*s != '\0'){return 1 + my_strlen(s + 1);}else{return 0;}
}int main()
{char arr[10] = { "abcdaaaa" };int len = my_strlen(arr);printf("%d\n", len);return 0;
}

3.求n的阶乘。

int Fac(int n)
{if (n <= 1){return 1;}else{return n*Fac(n - 1);}
}
int main()
{int n = 0;scanf("%d", &n);int ret = Fac(n);printf("%d\n", ret);return 0;
}

4.求斐波那契数列底n个数的值。

int Fib(int n)
{if (n <= 2)return 1;elsereturn Fib(n - 1) + Fib(n - 2);
}int main()
{int n = 0;scanf("%d", &n);int ret = Fib(n);printf("%d\n", ret);return 0;
}

 5.字符串逆序(递归实现)【将参数字符串中的字符反向排列,不是逆序打印。】

思路:

逆置字符串,循环的方式实现非常简单

  1. 给两个指针,left放在字符串左侧,right放在最后一个有效字符位置

  2. 交换两个指针位置上的字符

  3. left指针往后走,right指针往前走,只要两个指针没有相遇,继续2,两个指针相遇后,逆置结束

#include <stdio.h>
void reverse_string(char* arr)
{int len = strlen(arr);char tmp = *arr;*arr = *(arr + len - 1);*(arr + len - 1) = '\0';if (strlen(arr+1)>=2)reverse_string(arr + 1);*(arr + len - 1) = tmp;
}
/*或者不用指针表示:
int my_string(char* str)
{int count = 0;while (*str != '\0'){count++;str++;}return count;
}void reverse_string(char str[])
{int len = my_string(str);int tmp = str[0];str[0] = str[len - 1];str[len - 1] = '\0';if (my_string(str + 1) >= 2){reverse_string(str + 1);}str[len - 1] = tmp;
}
*/
int main()
{char arr[] = { "abc" };reverse_string(arr);printf("%s", arr);
}

6.计算一个数的每位之和(递归实现)

#include <stdio.h>
int DigitSum(int n)
{if (n > 9){return DigitSum(n / 10) + n % 10;}elsereturn n;
}int main()
{int n = 0;scanf("%d", &n);int ret = DigitSum(n);printf("%d\n", ret); 
}

7.递归实现n的k次方 

#include <stdio.h>
int pow(int n, int k)
{if (k == 0)return 1;else if (k >= 1)return n*pow(n, k - 1);
}
int main()
{int n = 0;int k = 0;scanf("%d %d", &n, &k);int ret = pow(n, k);printf("%d\n", ret);return 0;
}

8.  求 1+2+3....+n 的值 。

#include <stdio.h>
int sum(int n)
{if (n == 1)return 1;  // 出口 (必要的)elsereturn (sum(n - 1) + n);  //根据表达式 F(n)=f(n-1)+n  取等号后边式子 称为 递推关系式 
}
int main()
{int n = 0;scanf("%d", &n);int ret = sum(n);printf("%d\n", ret);/*int num = sum(100);printf("%d\n", num);*/return 0;
}

9. 已知一个整形数组,求出前n项数字之和。

#include <stdio.h>
int sum(int arr[], int n)
{if (n == 0)return arr[0];elsereturn sum(arr, n - 1) + arr[n];
}
int main()
{int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int ret = sum(arr, 4);printf("%d\n", ret);return 0;
}

10.  求一个已知数组里面前n个数字里面的最大值 (下标为n计算)

#include <stdio.h>
int max(int arr[], int n)
{if (n == 0)return arr[0];else if (max(arr, n - 1) > arr[n])return max(arr, n - 1);elsereturn arr[n];
}
int main()
{int arr[] = { 7, 4, 8, 6, 3, 2, 9, 11, 5 };int n = 0;scanf("%d", &n);int ret = max(arr, n);printf("%d\n", ret);return 0;
}

11.  递归中的冒泡排序

void bubble(int arr[], int L, int R)
{if (L < R){int i = 0;for (i = L; i <= R - 1; i++){if (arr[i] > arr[i + 1]){int tmp = arr[i];arr[i] = arr[i + 1];arr[i + 1] = tmp;}}bubble(arr, L, R - 1);}
}
int main()
{int i = 0;int arr[7] = { 7, 6, 5, 4, 3, 2, 1 };bubble(arr, 0, 6);for (i = 0; i < 7; i++){printf("%d ", arr[i]);}return 0;
}

12.求两数最大公约数 

int gcd(int a, int b)
{if (a%b == 0)return b;else{int r = 0;r = a%b;return gcd(b, r);}
}
int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);int ret = gcd(a, b);printf("%d\n", ret);
}

总结:

什么时候用递归:


1.当解决一个问题递归和非递归都可以使用,且没有明显问题。那就可以使用递归。


2.当解决一个问题递归写起来很简单,非递归比较复杂,且递归没有明显问题,那就用递归。

3.如果说用递归解决问题,写起来简单,但是有明显问题,那就不能使用递归。得写出非递归的方式来解决。

小tips :

 递归想的深入了,很容易被绕进去,这时我们就要记住“ 我们是懒懒的老和尚,计算机就是忙碌的小和尚,我们不要管他们。”  把它想成,在还没有到达递归函数出口位置时,在做重复的事情就可以了。既然是重复的事情就没有必要每一样都去验证了 。


http://lihuaxi.xjx100.cn/news/284318.html

相关文章

关于KN95口罩:可以使用多久?要不要呼吸阀?怎么佩戴?

点击上方蓝色字体&#xff0c;选择“设为星标”优质文章&#xff0c;及时送达来源 | 哆来咪咪再说一遍&#xff1a;一定要戴口罩&#xff01;冠状病毒在人与人之间传播&#xff0c;通常是在某人接触到感染者的分泌物的时候。病毒的传染力直接影响了传播途径。目前流行的新型冠状…

39个国外SCI抢发6万篇中国英文论文?然而,真正的问题是……

近来&#xff0c;学界接连曝光的多起案件背后&#xff0c;我们不难看出&#xff1a;发表高质量杂志或期刊论文&#xff0c;作为评价国内科研工作者能力的主要指标之一&#xff0c;在规则建设完善方面与国内真实的科研发展却是不相衬的。 科技界有这样一种做法&#xff0c;先把自…

JavaScript中的普通函数与构造函数比较

问题 什么是构造函数&#xff1f;构造函数与普通函数区别是什么&#xff1f;用new关键字的时候到底做了什么&#xff1f;构造函数有返回值怎么办&#xff1f;构造函数能当普通函数调用吗&#xff1f; thisthis永远指向当前正在被执行的函数或方法的owner。例如&#xff1a; 123…

用C语言实现三子棋游戏(附上思路+项目展示+源代码)

文章目录前言一、三子棋游戏整体实现思路二、实现步骤分模板实现 &#xff08;以及具体应用实列&#xff09;1.test.c 源文件讲解&#xff1a;2. game.c 源文件讲解&#xff1a;3.game.h 源文件讲解三 game.c 源文件整体展示总结前言 在初步学习C语言初阶知识后&#xff0c;我…

37岁程序员被裁,120天没找到工作,无奈去小公司,结果懵了...

欢迎关注&#xff1a;视学算法&#xff0c;每日好文章&#xff01;综合自网络从短期来看&#xff0c;程序员的确算是个不错的工作&#xff0c;薪水也比一般岗位高很多&#xff0c;但是从长远来看&#xff0c;程序员的中年危机会比其他岗位来的更早&#xff0c;很多程序员只有到…

Distroless加固容器安全

谷歌现在通过提供 Distroless 镜像向全世界开放这种能力。谷歌构建的这些镜像的目标是只包含你的应用程序及其依赖项&#xff0c;同时它们将没有常规 Linux 发行版的所有特性&#xff0c;包括 shell。使用Distroless镜像来保护Kubernetes上的容器。容器改变了我们看待技术基础设…

GAN实战——书法字体生成练习赛开始报名啦!

生成式对抗网络&#xff08;GAN&#xff09;是近年来大热的深度学习模型。目前GAN最常使用的场景就是图像生成&#xff0c;作为一种优秀的生成式模型&#xff0c;GAN引爆了许多图像生成的有趣应用。在图像生成模型的质量上&#xff0c;生成对抗网络技术可以说实现了飞跃&#x…

用C语言实现扫雷小游戏(附上思路+项目展示+源代码)

文章目录前言一、扫雷小游戏整体思路讲解。二、game.c各游戏功能函数的讲解1.InitBoard 初始化数组函数讲解2.DisplayBoard 打印格子函数讲解3.Setmine 电脑生成雷 函数讲解4.GetMineCount 格子表示周围雷的个数 函数讲解5.FindMine 排雷函数实现game.c源代码展示&#xff1a;三…