目录
1、什么是递归?
2、递归的两个必要条件
3、递归的练习
3.1 接受一个整型值(无符号),按照顺序打印它的每一位
3.2 编写函数不允许创建临时变量,求字符串的长度
3.3 求第n个斐波那契数
3.4 字符串逆序(递归实现)
总结
1、什么是递归?
程序调用自身的编程技巧称为递归( recursion )。递归做为一种算法在程序设计语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的主要思考方式在于:把大事化小
2、递归的两个必要条件
- 存在限制条件,当满足这个限制条件的时候,递归便不再继续。
- 每次递归调用之后越来越接近这个限制条件。
3、递归的练习
3.1 接受一个整型值(无符号),按照顺序打印它的每一位
例如:
输入: 1234 ,输出 1 2 3 4.
使用递归的方法代码如下:
#include <stdio.h>
void print(int n)
{
if(n>9)
{
print(n/10);
}
printf("%d ", n%10);
}
int main()
{
int num = 1234;
print(num);
return 0;
}
其递归过程如下:
3.2 编写函数不允许创建临时变量,求字符串的长度
递归代码如下:
#include<stdio.h>
int my_strlen(char* s)
{
if (*s == '\0')
{
return 0;
}
return 1 + my_strlen(s + 1);
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d", len);
return 0;
}
3.3 求第n个斐波那契数
递归代码如下:
#include<stdio.h>
int Fib(int n)
{
if (n <= 2)
{
return 1;
}
else
{
return Fib(n - 1) + Fib(n - 2);
}
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d", ret);
return 0;
}
但是我们会发现
有问题:使用 Fib
这个函数的时候如果我们要计算第
50
个斐波那契数字的时候特别耗费时间。
为什么呢?因为 F
ib
函数在调用的过程中有很多计算其实在一直重复。我们可以用迭代这样来写。
代码如下:
#include<stdio.h>
int Fib(int n)
{
int a = 1;
int b = 1;
int c = 1;
while (n >= 3)
{
c = a + b;
a = b;
b = c;
n--;
}
return c;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d", ret);
return 0;
}
3.4 字符串逆序(递归实现)
编写一个函数 reverse_string(char * string)(递归实现)
实现:将参数字符串中的字符反向排列,不是逆序打印。
要求:不能使用C函数库中的字符串操作函数。
比如有 char arr[] = "abcdef",逆序之后数组的内容变成:fedcba。
递归代码如下:
#include<stdio.h>
#include<string.h>
void reverse_string(char* str)
{
int len = strlen(str);
char temp = *str;
*str = *(str + len - 1);
*(str + len - 1) = '\0';
if (strlen(str + 1) >= 2)
{
reverse_string(str + 1);
}
*(str + len - 1) = temp;
}
int main()
{
char arr[] = "abcdef";
reverse_string(arr);
printf("%s", arr);
return 0;
}
也可以用循环的方式来实现,其思路为:
- 给两个指针,left放在字符串左侧,right放在最后一个有效字符位置
- 交换两个指针位置上的字符
- left指针往后走,right指针往前走,只要两个指针没有相遇,继续2,两个指针相遇后,逆置结束
函数部分代码如下:
void reverse_string(char* arr)
{
char *left = arr;
char *right = arr+strlen(arr)-1;
while(left<right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
总结
- 许多问题是以递归的形式进行解释的,这只是因为它比非递归的形式更为清晰。
- 但是这些问题的迭代实现往往比递归实现效率更高,虽然代码的可读性稍微差些。
- 当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开销。