关闭

斐波纳契数列不同实现比较

标签: cstruct递归enum优化
294人阅读 评论(0) 收藏 举报
分类:

斐波纳契数列形如:0,1,2,3,5,8,13,....。该序列的通用方程是:Fib(n)=Fib(n-1)+Fib(n-2).
1.使用递归

unsigned RecursiveFib(unsigned n)
{
	if (n <= 1)
		return n;
	return RecursiveFib(n-1) + RecursiveFib(n-2);
}


eg:RecursiveFib(0xFF); 信不信由你,这个简单函数的时间复杂度是指数级的,它非常低效。

2.使用循环

unsigned RecursiveFib(unsigned n)
{
	if (n <= 1)
		return n;

	unsigned f_2 = 0;
	unsigned f_1 = 1;
	unsigned f;
	for (unsigned i = 2; i <= n; i ++)
	{
		f = f_1 + f_2;
		f_2 = f_1;
		f_1 = f;
	}

	return f;
} 


eg:RecursiveFib(0xFFFFFF);解决了1中低效的问题。

3.使用模板函数

template<unsigned N> struct Fib
{
	enum
	{
		Val = Fib<N-1>::Val + Fib<N-2>::Val
	};
};

template <> struct Fib<0> {enum{Val = 0};};
template <> struct Fib<1> {enum{Val = 1};};

#define RecursiveFib3(n) Fib<n>::Val 


eg:RecursiveFib(4);
关于此模板化版本需要注意以下几点:
.模板函数并不是真正的函数--它是叫作Val的枚举整数,在编译期递归生成。语句Val = Fib<N-1>::Val + Fib<N-2>::Val不常见,但是合法。
.Fib被定义为结构,以简化标记。在默认情况下结构数据是公用的,这也正是我们所需要的。
.模板参数N用于指定函数的输入。这种模板参数的使用并不常见,但完全可行。例数,std::bitset<N> 用N的数值作为它的模板参数来定义表示位域的位数。数字参数必须在编译期被获知,如果当i还是可变的变量时调用RecursiveFib(i),则会产生编译错误。
.要中止递归,需要正确地处理结束条件。对于斐波纳契数来说,结束条件就是当N为0和1时。在模板中处理基本情况的方法是使用模板特化。标记了template<>的,表示为模板特化。当N为0和1时,Val=N.

分析编译程序如何计算RecursiveFib(4):

=Fib<4>::Val
=Fib<3>::Val + Fib<2>::Val
=Fib<2>::Val + Fib<1>::Val + Fib<1>::Val + Fib<0>::Val
=Fib<1>::Val + Fib<0>::Val + 1 + 1 + 0
=1 + 0 + 1 + 1 + 0
=3


由于所有的输入在编译期都确定了,所以编译程序可以将RecursiveFib(N)换算为常量。换句话来说,编译程序可以生成与以下完全等价的代码:

std::cout<<3;//std::cout<<RecursiveFib(4)

该方法可以成为你C++工具包中有用工具。你很可能会有指数级运行时间不能降为常数级运行时间的情况,通过使用模板无编程,就可以通过增加额外的编译时间来降低程序的执行时间。对于游戏来说,执行时间通常比编译时间更重要,所以这项技术也将非常有用。

0
0

猜你在找
【直播】机器学习&数据挖掘7周实训--韦玮
【套餐】系统集成项目管理工程师顺利通关--徐朋
【直播】3小时掌握Docker最佳实战-徐西宁
【套餐】机器学习系列套餐(算法+实战)--唐宇迪
【直播】计算机视觉原理及实战--屈教授
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之矩阵--黄博士
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之凸优化--马博士
【套餐】Javascript 设计模式实战--曾亮
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:4162次
    • 积分:95
    • 等级:
    • 排名:千里之外
    • 原创:5篇
    • 转载:7篇
    • 译文:0篇
    • 评论:0条
    文章分类