C语言(函数递归)

函数递归存在着两个必要条件:

1.递归存在限制条件,满足了限制条件,递归就会停止

2.每一次递归都会接近这个限制条件

有了这两个条件,我们才能使递归正确运行。

中心思想:大事化小,把大问题拆分为小问题去解决,递归的过程呢,我们把它想象为递推与回归

今天我会运用几个简单的练习题为大家进行分析,并分析其中遇到的小问题

目录

练习一:接收一个整形值(无符号),按顺序打印他的每一位

练习二:编写函数不允许创建临时变量,求字符串长度

练习三:求N的阶乘(不考虑溢出)

练习四:求第N个斐波那契数列(不考虑溢出)

非递归与栈溢出

练习一:接收一个整形值(无符号),按顺序打印他的每一位

例如:1234,输出1 2 3 4

void Print(int n)
{
	if (n < 9)
	{
		printf("%d ", n);
		return;
	}
	Print(n / 10);
	printf("%d ", n%10);
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	Print(n);
}

看完上面两图的讲解是否对递归有了初步的认识呢,有了两个必要条件,就可以递归下去

 练习二:编写函数不允许创建临时变量,求字符串长度

我们一般求字符串长度一般都会使用strlen函数对不对,但是我们要知道的是,strlen的底层实现是用了变量count去计数,这样就违背了题目的要求。那么我们应该怎么办呢?让我们来看一段代码

int my_strlen(char* str)
{
	if (*str == '\0')
	{
		return 0;
	}
	return 1 + strlen(str + 1);
}
int main()
{
	char* arr = "abc";
	int len = my_strlen(arr);
	printf("%d ", len);
	return 0;
}

此时我们并没有创建临时变量就完成就计算

 以上图解就是递归的详细过程,使用几行代码就完成了递归的过程

 练习三:求N的阶乘(不考虑溢出)

一般我们使用循环非常简单的就写出了N的阶乘,那么我们今天来看看用递归的方式怎么写

思路:求N的阶乘我们可以理解为 N*N-1的阶乘 限制条件就是当N到1的时候,1的阶乘就是1,

让我们来看代码

int factorial(int n)
{
	if (n == 1)
	{
		return 1;
	}
	return n * factorial(n - 1);
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	printf("%d ", factorial(n));
}

我们知道了两个必要条件就可以写出递归,一个是限制条件 递推到n =1的时候,意味着1的阶乘是1,就可以开始回归了, 第二个是去解决限制条件,就是n的阶乘是n*n-1的阶乘,让n不断变小,去接近N=1;

 练习四:求第N个斐波那契数列(不考虑溢出)

 斐波那契数列想必大家都知道: 1  1  2  3  5  8  13  21  34   55  ....

第一个数加第二个数 等于第三个数 , 我们在不考虑效率和空间的情况下,让我们用递归思路解

让我们来看代码

int fib(int n)
{
	if (n <= 2)
	{
		return 1;
	}
	return fib(n - 1) + fib(n - 2);
}
int main()
{
		int n = 0;
		scanf("%d", &n);
		printf("%d ", fib(n));
}

我们可以看到用少量简洁的代码就写出了斐波那契数列,但是,我们假如要去求第50个斐波那契数列,那么我们的电脑估计会很头疼,这需要非常大,且重复的计算,并且一直递归还会占用我们栈区大量的空间。

此时我们应该怎么解决呢,可能大家也都知道了,那就是改成非递归,让我们来看一下下一个模块

非递归与栈溢出

让我们把求第N个斐波那契数列改为非递归看一看他的效率

int fib(int n)
{
	int a = 1;
	int b = 1;
	int c = 1;
	while (n>=3)
	{
		a = b;
		b = c;
		c = a + b;
		n -= 1;
	}
	return c;
}
int main()
{
		int n = 0;
		scanf("%d", &n);
		printf("%d ", fib(n));
}

把递归改成非递归后,效率里面提升上来了,求第50个斐波那契数列不需要使用那么多冗余的计算。

 通过不断循环计算,就可以高效的求出第N个斐波那契数列.

栈溢出:我们要知道栈的空间是有限的,递归如果一直递推下去,每一次递推都开辟新的栈帧,那么总会把栈空间填满的,所以我们在使用递归的时候一定要注意这个问题,如果栈溢出编译器就会报错,stack overflow.

总结:

我们要写递归的时候要思考什么时候可以用递归什么时候不可以用递归。

有的时候如果用递归会出现,栈溢出,效率慢等问题,那么这个时候我们就要去改非递归,或者用静态变量放到空间比较大的堆上。

那么我们什么时候可以写呢:

如果使用递归非常容易想到并且没有明显的副作用,那就可以使用。

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值