目录
1. 函数递归
1.1什么是递归?
程序调用自身的编程技巧称为递归( recursion)。
递归做为一种算法在程序设计语言中广泛应用。
一个过程或函数在其定义或说明中有直接或间接 调用自身的 一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解, 递归策略 只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归的主要思考方式在于:把大事化小
这里为大家写一个最简单的递归
#include<stdio.h>
int main()
{
printf("hehe\n");
main();
return 0;
}
这里在函数内部自己调用了自己,这里的话就会一直打印hehe,直到栈溢出。
1.2递归的两个必要条件
存在限制条件,当满足这个限制条件的时候,递归便不再继续。
每次递归调用之后越来越接近这个限制条件
1.3 练习
接受一个整型值(无符号),按照顺序打印它的每一位。
例如: 输入:1234,输出 1 2 3 4.
在解决这个题目时,我们有一下思路
当我们想把1234一一打印在屏幕上的话我们会发现,最容易打印的是4,直接用1234%10=4
然后我们再用1234/10就得到了123,以此往下推,如图所示。
上图的思路我们用代码实现
#include<stdio.h>
void print(unsigned int n)
{
while (n)
{
printf("%d",n%10);
n = n / 10;
}
}
int main()
{
unsigned int num = 0;
scanf("%d",&num);
//写一个函数打印num的每一位
print(num);
return 0;
}
但是这里的问题是没有按照题目要求顺序打印,在这里是倒序打印。
这时候我们就要变换思路,我们这时就想,当print(1234)时
我们能不能拆成,先打印 123 的每一位,再打印(4)
然后我们拆成, 打印 12 的每一位,再加上3,再加上4
然后我们拆成 打印 1 的每一位,再加上2,再加上3,再加上4
print(n)
print(n/10)
printf("%d",n%10)
这里没看懂没关系,下面有画图解释
我们先看一下代码实现和运行结果:
#include<stdio.h>
void print(unsigned int n)//n=1234
{
if(n>9)//大于一位数
{
print(n / 10);
}
printf("%d", n % 10);
}
int main()
{
unsigned int num = 0;
scanf("%d", &num);
//写一个函数打印num的每一位
print(num);
return 0;
}
1.4 画图解释
我们先来了解递归的意思
递归实际上时两个词
递——递推
归——回归
这里假设我们输入的值时1234
递推我们用红色表示
回归我们用蓝色表示
1.4 练习2
编写函数不允许创建临时变量,求字符串的长度。
得知题目,我们就可以写发出以下代码
由题可得,就是让我们不使用strlen的情况下,自己模拟strlen函数,关键时参数该怎么写。
首先我们要知道,数组名其实就是首元素的地址
数组[" hello "]中,里面存放的就是[ h e l l o \0]
首元素是 h ,他是一个字符的地址,所以我们要用字符指针来接收它
首先str指向了 h
字符串的结束标志是 \0
这里我们要判断就是 *str!='\0' 这里表示如果不等于\0就代表还能读取到数据
这时候我们就设置一个计数器 count++、
然后我们需要让str往后走一步 str++
只要把这个写成循环即可
字符指针+1,向后跳一个字符
#include<stdio.h>
int my_strlen(char* str)
{
int count = 0;//计数器
while (*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
char arr[] = "hello";
//定义函数
int len = my_strlen(arr);
printf("%d\n",len);
return 0;
}
运行结果:
但是这里我们这里又发现不符合题目要求
编写函数不允许创建临时变量,求字符串的长度
在上述代码中,我们创建了一个变量计数器,count。
在上面我们的判断条件是 *str!='\0'
我们也可以这样判断
my_strlen中我们放的是hello
my_strlen("hello");
当我们判断子一个字符不是\0时,他的长度至少是一个字符,就i可以转换成
1+my_strlen("ello");
然后发现不是\0,就再拿下来,以此内推
1+1+my_strlen("llo");
1+1+1my_strlen("lo");
1+1+1+1my_strlen("o");
1+1+1+1+1my_strlen("");
这里空字符串肯定是0
1+1+1+1+1+0=5
这样我们就可以这样理解,如果第一个字符不等于\0时,返回1+my_strlen(str+1)
如果第一个字符等于\0,那就直接返回0
#include<stdio.h>
int my_strlen(char* str)
{
if (*str != '\0')
return 1 + my_strlen(str + 1);
else
return 0;
}
int main()
{
char arr[] = "hello";
//定义函数
int len = my_strlen(arr);
printf("%d\n",len);
return 0;
}
注意:
1. 许多问题是以递归的形式进行解释的,这只是因为它比非递归的形式更为清晰。
2. 但是这些问题的迭代实现往往比递归实现效率更高,虽然代码的可读性稍微差些。
3. 当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开 销。