【C语言学习】函数递归与栈溢出与迭代

函数递归:程序调用自身。一个过程或函数数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归

主要思考方式在于:大事化小

递归的简单示例(存在错误):

#include 
int main()
{
	printf("hehe\n");
	main();
	return 0;
}

打印结果:

【C语言学习】函数递归与栈溢出与迭代_第1张图片

 错误:通过调试功能运行程序,出现报错(Stack overflow——栈溢出)

【C语言学习】函数递归与栈溢出与迭代_第2张图片

关于栈溢出的详细解释:

内存使用时主要划分为栈区(又名栈/堆栈)(存放局部变量,函数形参,调用函数时返回值等临时变量),堆区(又名堆)(用于动态内存分布,如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;
}

一些功能可以使用迭代,也可以使用递归,将上述程序利用递归进行编程:

【C语言学习】函数递归与栈溢出与迭代_第3张图片

#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...)。(不考虑溢出)

递归:

【C语言学习】函数递归与栈溢出与迭代_第4张图片

#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,则程序需要进行长时间的运行。

【C语言学习】函数递归与栈溢出与迭代_第5张图片

迭代(效率大大提高):

#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;
}

你可能感兴趣的:(c语言,学习,算法)