函数递归
1.什么是递归?
函数调用自身的编程技巧称为递归(recursion)。
一个过程或函数在其定义或说明中有直接或间接的调用自身。
一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的的问题来求解,递归策略。
只需要少量的程序就可以描述出解题过程所需要的多次重复计算,大大减少程序的代码量。
递归的主要思考方法在于:把大事化小
递归小例题:
输入1324,输出:1 2 3 4,使用递归解决问题
# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void recursion(unsigned int x) {
if (x > 9) {
recursion(x / 10);//这里调用自身,不是个位数就再调用自身,最后最里面的那个将会输出个位数,次的会输出十位数,以此类推
}
printf("%d ", x % 10);//最后一个输出,输出“数字加空格:
}
int main() {
unsigned int num = 0;
scanf("%d", &num);
recursion(num);
return 0;
}
//输入:1234
//输出:1 2 3 4
2.递归的两个必要条件
-
存在限制条件,当满足条件的时候,递归便不再继续。
-
每次递归之后越来越接近这个限制条件。
没有限制条件的情况:
递归需要设置循环条件,否则会发生栈溢出问题
因为栈区是由内存空间的,不仅是局部变量和函数形参在栈区,函数的每次调用都会向栈区申请空间,不添加递归的终止条件,函数就会把栈区填满,发生栈区溢出的问题。
递归求字符长度:
当str
是一个指向字符串中某个字符的指针时,执行str++
操作会将str
指针移动到字符串中的下一个字符。
# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int my_strlen(char* str) {
int count = 0;
while (*str != '\0')//找最后一个字符
{
str++;// 将指针向前移动到下一个字符
count++;
}
return count;
}
int main() {
char arr[] = "abcd";
int num = my_strlen(arr);
printf("%d", num);
}
使用递归求字符长度:
int my_strlen(char* str) {
if (*str != '\0')//检查是否是空字符,这里为了与字符比较,所以需要单引号’,而不是双引号”
{
return 1 + my_strlen(str + 1);
}
else
{
return 0;
}
}
int main() {
char arr[] = "abcd";
int num = my_strlen(arr);
printf("%d", num);
}
3.递归与迭代
使用递归函数求阶乘
# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int secursion_jc(int zx) {
if (zx>1)
{
return zx * secursion_jc(zx - 1);
}
else if (zx == 1)
{
return 1;
}
else// 假设负数和非正整数输入返回-1作为错误标识
{
return -1;
}
}
int main() {
int num = 0;
scanf("%d", &num);
int result = secursion_jc(num);
if (result!=-1)
{
printf("%d", result);
}
else
{
printf("好像出错了!");
}
}
迭代的写法:
#include <stdio.h>
int iterative(int n) {
int factorial = 1;
for (int i = 1; i <= n; i++) {
factorial *= i;
}
return factorial;
}
int main() {
int num = 10;
int result = iterative(num);
printf("%d的阶乘是:%d\n", num, result);
return 0;
}
求斐波那契数
斐波那契数列是指这样一个数列:1,1,2,3,5,8,13,21,34,55,89……这个数列从第3项开始 ,每一项都等于前两项之和。
使用递归求斐波那契数:
使用递归求斐波那契数,每个数都需要计算三次,占用了多数内存,所以不推荐。
# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int fbnq(int num) {
if (num <=2)
{
return 1;
}
else {
//一直在寻找前两位数,知道找到fbqn(1) 1和fbnq(2) 2得到fbnq(3) 3,2和3再得到4等于5
//就是向下查找前两位数,但是没有具体的数值,知道遇到了fbnq(1)和fbnq(2),然后向上传值计算。
return fbnq(num - 1) + fbnq(num - 2);
}
}
int main() {
int n = 0;
scanf("%d", &n);
int result = fbnq(n);
}
使用递归操作大数可能会发生栈溢出的问题,要解决这种问题可以:
-
使用其他的方法实现函数
-
使用static修饰函数的局部变量,缓解局部变量的空间(只是平衡以下内存,太大还是会溢出的)
使用迭代求斐波那契:
没有占用多余的空间,比较推荐使用。
int fbnq(int n) {
int c = 0;
int a = 1;
int b = 1;
while (n>=3)
{
c = a + b;//自下而上,正常的顺序求斐波那契数,一个一个的加上去
a = b;
b = c;
n--;
}
return c;
}
int main() {
int n = 0;
scanf("%d", & n);
int result = fbnq(n);
printf("%d", result);
}