- 编写函数不允许创建临时变量,求字符串的长度。
编程思路:
(1)首先来编写一个求字符串长度但不编写自定义函数的代码。
#include <stdio.h>
#include <string.h>
int main()
{
int len = strlen("CSDN");
printf("%d\n", len);
return 0;
}
运行结果:
4
这里使用 srtlen 库函数可以来帮助实现。srtlen 库函数用来返回字符串长度(不包括结尾的“\0”)。
(2)然后来编写一个函数,求字符串的长度,也就是模拟实现 strlen 函数。
编写函数需要注意参数的传递:
- 主函数需要传递一串字符串,而传递字符其实是传递字符的地址,就相当于数组中元素的传递。
- 自定义函数需要接收一串字符串,可以用指针来接受数组中字符串的地址。
这里运用了函数的传址调用,详见https://mp.csdn.net/mp_blog/creation/editor/133105119
代码示例:
#include <stdio.h>
#include <string.h>
int my_strlen(char* p) //接收数组中字符串地址
{
int count = 0;
while (*p != '\0')//遇到\0停止循环
{
count++; //字符串个数计数
p++;//找下一个字符串
}
return count;//返回字符串个数
}
int main()
{
char arr[] = "CSDN";//定义数组来存放字符串
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
运行结果:
4
(3)上一个代码中函数创建了临时变量 count ,那么如何设计一个函数不创建临时变量的条件下还可以求出字符串长度。
递归函数的方式来试一下:
在上一个函数的基础上,去掉变量 count ,用上一篇函数递归博客(https://mp.csdn.net/mp_blog/creation/editor/133252995)中的方法来设计递归的思路。
函数”递“的思路:
- function(CSDN) :向函数中传入字符串CSDN,函数用指针先接收到第1个字符‘C’的地址。
- function(SDN) :指针变量+1,指针指向下一个字符,函数接收到第2个字符‘S’的地址。
- function(DN) :指针变量再+1,指针指向下一个字符,函数接收到第3个字符‘D’的地址。
- function(N) :指针变量再+1,指针指向下一个字符,函数接收到第4个字符‘N’的地址。
- function( ) :指针变量再+1,指针指向下一个字符,遇到‘\0’后开始返回。
函数”归“的思路:
- function( ) :返回0;
- function(N) +1 :返回上一层函数+1
- function(DN) +1+1:返回上一层函数+1+1
- function(SDN) +1+1+1 :返回上一层函数+1+1+1
- function(CSDN) +1+1+1+1 :返回上一层函数+1+1+1+1 ,这里其实是要跳出函数,并且返回了值4.
- 最后打印结果显示为4
代码示例:
#include <stdio.h>
#include <string.h>
int my_strlen(char* p)
{
if (*p != '\0')
return 1 + my_strlen(p + 1);
else
return 0;
}
int main()
{
char arr[] = "CSDN";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
运行结果:
4
函数递归还有两个必要条件:
- 存在限制条件,当满足这个限制条件的时候,递归便不再继续。
- 每次递归调用之后越来越接近这个限制条件。
这里 *p != '\0' 条件下返回 0,是函数递归的限制条件。
而return 1 + my_strlen(p + 1); 使递归调用之后越来越接近这个限制条件。
2.求n的阶乘。
编程思路:如果算5的阶乘
- function(4)*5
- function(3)*4*5
- function(2)*3*4*5
- function(1)*2*3*4*5
所以得出:n*function(n-1);
代码示例:
#include <stdio.h>
int fun(int x)
{
if (x <= 1)
return 1;
else
return x * fun(x - 1);
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = fun(n);
printf("%d", ret);
return 0;
}
运行结果:
5
120
可是当阶乘的数字有点大的时候,函数递归的方法会效率低下,所以不太适用。迭代也就是循环的方式可能会更好一些。
代码示例:
#include <stdio.h>
int fun(int x)
{
int i = 1;
int ret = 1;
for (i = 1; i <= x; i++)
{
ret = ret * i;
}
return ret;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = fun(n);
printf("%d", ret);
return 0;
}
运行结果:
5
120
12
479001600
3.求第n个斐波那契数。(不考虑溢出)
斐波那契数列:1,1,2,3,5,8,13,21,34,55......
第n个数 = (第n-2个数) + (第n-1个数)
代码示例1:函数递归方式:
#include <stdio.h>
int fib(int x)
{
if (x <= 2)
return 1;
else
return fib(x - 2) + fib(x - 1);
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = fib(n);
printf("%d", ret);
return 0;
}
运行结果:
10
55
可是当斐波那契的数字位数有点大的时候,函数递归的方法会效率低下,所以不太适用。迭代也就是循环的方式可能会更好一些。
代码示例2:迭代方式
#include <stdio.h>
int fib(int x)
{
int a = 1;
int b = 1;
int c = 1;
while (x > 2)
{
c = a + b;
a = b;
b = c;
x--;
}
return c;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = fib(n);
printf("%d", ret);
return 0;
}
运行结果:
6
8
总结
- 许多问题是以递归的形式进行解释的,这只是因为它比非递归的形式更为清晰。
- 但是这些问题的迭代实现往往比递归实现效率更高,虽然代码的可读性稍微差些。
- 当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开销。