36-递归与迭代

36-1 用递归和迭代解决问题

1、求n的阶乘

公式:

n!=1×2×3×...×(n-1)×n。用递归方式定义:0!=1,n!=(n-1)!×n。

代码1:

我们先回忆一下之前用循环怎么实现的吧

非递归,也可称迭代

int main()
{
	int n = 0;
	scanf("%d", &n);
	int i = 1;
	int ret = 1;
	for (i = 1; i <= n; i++)
	{
		ret = i * ret;
	}
	printf("%d\n", ret);
	return 0;
}

运行结果:

代码2:

递归

int fac(num)
{
	if (num > 1)
	{
		return num * fac(num - 1);
	}
	else
	{
		return 1;
	}
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = fac(n);
	printf("%d\n", ret);
	return 0;
}

运行结果:

有些时候,并不适合用递归

2、求第n个斐波那契数

斐波那契数列:在数学上,斐波那契数列可以通过递推的方式定义,从第三项开始,每一项都等于前两项之和。具体的递推公式为F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2),其中n≥2且n属于自然数集。

代码1:递归方法

int F(n)
{
	int ret = 0;
	if (n >= 2)
	{
		 return F(n - 1) + F(n - 2);
	}
	else if (0 == n)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = F(n);
	printf("%d\n", ret);
	return 0;
}

 运行结果:

但是,这里会有大量重复的计算!严重浪费时间

我们可以进行一个测试

int count = 0;  //计数器
int F(n)
{
	int ret = 0;
	if (n == 3)
	{
		count++;  //计数,一共算了多少次第三个斐波那契数
	}
	if (n >= 2)
	{
		 return F(n - 1) + F(n - 2);
	}
	else if (0 == n)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = F(n);
	printf("%d\n", ret);
	printf("count=%d\n", count);
	return 0;
}

运行结果:

竟然算了将近4万次!!!

效率太低了,用递归太不合适啦!我们试试迭代吧~~~

代码2:迭代

①for循环

int Fib(n)
{
	if (n >= 2)
	{
		int sum = 0;
		int i = 0;
		int n1 = 1;  //第一个数
		int n2 = 1;  //第二个数
		for (i = 0; i < n-2; i++)  //直接从第3个算起
		{
			sum = n1 + n2;
			n1 = n2;
			n2 = sum;
		}
		return sum;
	}
	else if(0==n)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = Fib(n);
	printf("%d\n", ret);
}

②while循环(该代码默认n>=1)

int Fib(n)
{
	int n1 = 1;
	int n2 = 1;
	int n3 = 1;
	while (n >= 3)
	{
		n3 = n1 + n2;
		n1 = n2;
		n2 = n3;
		n--;
	}
	return n3;
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = Fib(n);
	printf("%d\n", ret);
}

再使用这两个代码进行测试,你会发现代码运行速度明显比递归的速度快

注意:如果用特别大的数测试,可能会得到负值,这是因为溢出了,关于溢出的问题这里不进行展开

36-2 权衡递归与迭代的使用

1、许多问题是以递归的形式进行解释的,这只是因为它比非递归的形式更为清晰。

2、但是这些问题的迭代实现往往比递归实现效率更高,虽然代码的可读性稍微差些。

3、当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开销。

4、如果使用递归没有出现明显的问题,递归可以使用;但是如果有类似的明显问题,则采用非递归的方法解决。

5、递归的层次太深,会出现栈溢出的现象。

应对策略:

①将递归改写成非递归

②使用static对象替代nonstatic局部对象。在递归函数设计中,可以使用static对象替代nonstatic局部对象(即栈对象),这不仅可以减少每次递归调用和返回时产生和释放nonstatic对象的开销,而且static对象还可以保存递归调用的中间状态,并且可为各个调用层所访问。

当然,这只是一些可能的解决方案,并不一定真的能够解决栈溢出的问题

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值