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

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

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

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

#include <stdio.h>
int main()
{
	printf("hehe\n");
	main();
	return 0;
}

打印结果:

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

关于栈溢出的详细解释:

内存使用时主要划分为栈区(又名栈/堆栈)(存放局部变量,函数形参,调用函数时返回值等临时变量),堆区(又名堆)(用于动态内存分布,如malloc,free,calloc,realloc等),静态区(存放全局变量,静态变量)三块空间使用。每一次函数调用都会在栈区申请了一块空间(即某一个函数的栈帧空间,栈帧空间内存放函数的局部变量),当栈区空间耗尽,形成栈溢出。(注意:函数调用完成返回值后,相应的栈帧空间销毁,空间返回内存中)

由栈溢出得出关于函数递归的必要条件

1,不能死递归,设置跳出条件,当满足这个跳出条件的时候,递归便不再继续。

2,每次递归调用之后越来越接近这个跳出条件。

3,递归层次不能太深

递归练习1:接受一个整型值(无符号),按顺序打印它的每一位。例如:输入:1234      输出 :1 2 3 4

#include <stdio.h>
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 <stdio.h>
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 <stdio.h>
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 <stdio.h>
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 <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;
}

但是此代码效率太低——进行了重复大量的计算!若输入50,则程序需要进行长时间的运行。

迭代(效率大大提高):

#include <stdio.h>
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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值