函数递归:程序调用自身。一个过程或函数数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归
主要思考方式在于:大事化小
递归的简单示例(存在错误):
#include
int main()
{
printf("hehe\n");
main();
return 0;
}
打印结果:
错误:通过调试功能运行程序,出现报错(Stack overflow——栈溢出)
关于栈溢出的详细解释:
内存使用时主要划分为栈区(又名栈/堆栈)(存放局部变量,函数形参,调用函数时返回值等临时变量),堆区(又名堆)(用于动态内存分布,如malloc,free,calloc,realloc等),静态区(存放全局变量,静态变量)三块空间使用。每一次函数调用都会在栈区申请了一块空间(即某一个函数的栈帧空间,栈帧空间内存放函数的局部变量),当栈区空间耗尽,形成栈溢出。(注意:函数调用完成返回值后,相应的栈帧空间销毁,空间返回内存中)
由栈溢出得出关于函数递归的必要条件:
1,不能死递归,设置跳出条件,当满足这个跳出条件的时候,递归便不再继续。
2,每次递归调用之后越来越接近这个跳出条件。
3,递归层次不能太深
递归练习1:接受一个整型值(无符号),按顺序打印它的每一位。例如:输入:1234 输出 :1 2 3 4
#include
void print(unsigned int n)
{
if (n > 9)//跳出条件
{
print(n / 10);//接近跳出条件
}
printf("%d ", n % 10);
}
int main()
{
unsigned int num = 0;
scanf("%d", &num);
print(num);
return 0;
}
递归练习2:编写函数不允许创造临时变量,求字符串的长度。
#include
int my_strlen(char* str)//字符指针变量str此时存放了'f'的地址,即str指向'f'
{
if (*str != '\0')//跳出条件
return 1 + my_strlen(str + 1);//str + 1表示下一个字符的地址,使得函数调用完后逼近条件。
//return 1 + my_strlen(str++);存在问题:后置++:先使用后++,传递str,保留++后的值
//return 1 + my_strlen(++str);存在问题:前置++:先++后使用,传递++后的值,保留++后的值,虽然可以正常使用,但是保留下来的str的值发生改变
//使用递归时不建议使用++写法
else
return 0;
}
int main()
{
char arr[] = "fan";
//['f'] ,['a'] ,['n'] ,['\0']
printf("%d\n", my_strlen(arr));//my_strlen模拟实现strlen函数
//arr传送数组首元素'f'字符的地址
return 0;
}
大事化小
my_strlen("bit\0")
>1 + my_strlen("it\0")
>1 + 1 + my_strlen("t\0")
>1 + 1 + 1 + my_strlen("\0")
即1 + 1 + 1 + 0 = 3
迭代(包括循环等)
练习1:求n的阶乘(不考虑溢出)
迭代:
#include
int main()
{
int n = 0;
scanf("%d", &n);
int i = 0;
int ret = 1;
for(i = 1; i <= n; i++)
{
ret = ret * i;
}
printf("%d", ret);
return 0;
}
一些功能可以使用迭代,也可以使用递归,将上述程序利用递归进行编程:
#include
int Fac(int n)
{
if (n > 1)
return n * Fac(n - 1);
else
return 1;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fac(n);
printf("%d", ret);
return 0;
}
练习2:求第n个斐波那契数(1 1 2 3 5 8 13 21 34 55...)。(不考虑溢出)
递归:
#include
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;
}
但是此代码效率太低——进行了重复大量的计算!若输入50,则程序需要进行长时间的运行。
迭代(效率大大提高):
#include
int Fib(int n)
{
int a = 1;
int b = 1;
int c = 1;
while (n > 2)
{
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;
}