通过斐波那契数列分析递归与迭代时间差异

来源:互联网 发布:mac系统编辑word文档 编辑:程序博客网 时间:2024/05/06 12:24
今天在看一个公开课的时候看到了斐波那契数列的算法,忽然有了一点感想:不知道为什么大家在给别人讲这个数列的算法的时候讲的最多的就是递归的算法,明明递归的算法要比迭代的算法运行时间长很多,堆栈开销也要大很多,那为什么不给他们讲那种时间和空间开销都很小的迭代算法呢。
这是一个想法又出现在我的脑子里,迭代能比递归消耗多少时间和空间呢?答案我也不知道,当然我可以写个程序来验证一下,为什么不呢。于是我写了以下程序来检测时间开销:
在说程序代码之前,我们要考虑用什么来表示计算的时间呢?我的第一反应使用系统时间time_t,它是定义在time.h中的一个类型,表示一个日历时间,也就是从1970年1月1日0时0分0秒到此时的秒数,原型是:
 typedef long time_t;        /* time value */
可以看出time_t其实是一个长整型,由于长整型能表示的数值有限,因此它能表示的最迟时间是2038年1月18日19时14分07秒。悲剧了,因为系统时间精确到秒,而现在计算机的主频都很快,1秒钟程序可能已经计算结束了,所以我们要找到另一个方法来计算时间,这时就要使用clock函数了,函数原型:
 clock_t clock(void);
从定义可以看出clock返回一个clock_t类型,这个类型也定义在time.h中,原型是:
 typedef long clock_t;
clock_t也是一个长整型,表示的是从程序开始运行到执行clock函数时所经过的cpu时钟计时单元数。于是代码就出来了:

#include <iostream>
#include <time.h>

using namespace std;

int FibonacciRecursion(int num);
int FibonacciIterator(int num);

int main(){
 clock_t start = clock();
 int value;
 value = FibonacciRecursion(25);
 cout << value << endl;
 cout << "使用时间" << clock() - start << endl;
 start = clock();
 value = FibonacciIterator(25);
 cout << value << endl;
 cout << "使用时间" << clock() - start << endl;
 return 0;
}
int FibonacciRecursion(int num){
 if (num < 2)
  return 1;
 return FibonacciRecursion(num - 1) + FibonacciRecursion(num - 2);
}
int FibonacciIterator(int num){
 if (num < 2)
  return 1;
 int first = 1, second = 1;
 int value;
 for (int i = 2; i < num; i++){
  value = first + second;
  first = second;
  second = value;
 }
 return first + second;
}

非常有意思的是当时我想计算的是斐波那契数列的第10000个数值,呵呵,然后我就想当然的写下了 value = FibonacciRecursion(10000); 结果悲剧了,很明显我没有考虑到整形的表示范围是多少,我们可以简单地计算以下,以32个bit为例,整形的最大表示范围是:-2^31--(2^31-1),当然我们不知道这个数字是多少,但是可以简单地认为2^10=1000。那么也就是表示范围大概是在-2,000,000,000到2000,000,000之间。而斐波那契数列我们可以简单地表示为F(x)=2*F(x-1),当然这是不准确的,由于F(2)=2,我们可以简单地表示F=2^(X-1),也就是说F(32)可能就已经超出表示范围了。
当然F(10000)是可以计算的,这个问题之后在考虑,那么我们的计算结果是什么呢:

递归使用时间7
迭代使用时间0
结果很明显,迭代的时间使用的比递归使用的少的多。
0 0
原创粉丝点击