在编写程序中常常要不断优化算法,算法的好坏无非取决于时间和空间的消耗,其中的时间消耗也是我们最关心的问题,一些算法的时耗我们是可以很轻松的大概估计的,比如多个循环的叠加。当然也有许多情况是我们难以估计的,比如复杂的递归。这时候我们就需要一个工具来帮我们计算代码段的耗时情况。
这里我就举一个简单实用的方法。
c/c++提供了名为time的标准库,其中clock()函数可以返回从程序开始到clock()函数被调用这之前CPU走过的时钟计时单元数,当然这个单元数我们是难以直接识别的,这时候我们就需要一个能表示CPU时钟一秒钟所走过的时钟单位数常量,常用的是CLOCKS_PER_SEC和CLK_TCK。
具体使用方法如下:
#include<iostream>
#include<ctime> //调用time标准库
using namespace std;
int main()
{
clock_t start, end; //clock_t 是clock()的返回变量类型
start = clock(); //捕捉循环段开始的时间
for (int i = 0; i < 50000; i++)
for (int j = 0; j < 10000; j++);
end = clock(); //捕捉循环段结束的时间
cout << "代码经过的时间是" << (end-start) / CLK_TCK << endl; //两端时间相减再除以常量
return 0;
}
这样我们就可以了解我们的程序具体的时耗了
但是其中有几点值得注意:
- start和end应分别在被测代码段的前后,不在测试范围的代码要写在外面,如程序的准备工作。
- 计算机运行程序很快,许多代码段能瞬间被完成,当代码消耗时间小于一个时钟计时单元时,会无法正常显示耗时(输出耗时为0),这时我们可以将所测代码运行多遍,再将所得耗时除以运行次数,即可得到代码用时;或增大输入数据,来获得耗时。举个例子:
当我们想看看斐波拉契数列递归实现方法的时间耗时
#include<iostream>
#include<ctime>
using namespace std;
long long rpt(int n)
{
if (n == 1 || n == 2) return 1;
else return rpt(n - 1) + rpt(n - 2);
}
int main()
{
clock_t start, end;
start = clock();
rpt(20); //对递归函数计时
end = clock();
cout << "代码经过的时间是" << (end-start) / CLK_TCK << endl;
return 0;
}
不出所料:
没关系,我们让代码多运行几次,套个循环看看:
#include<iostream>
#include<ctime>
using namespace std;
long long rpt(int n)
{
if (n == 1 || n == 2) return 1;
else return rpt(n - 1) + rpt(n - 2);
}
int main()
{
clock_t start, end;
int i;
start = clock();
for(i=0;i<5000;i++) rpt(20); //多让代码运行几遍
end = clock();
cout << "代码经过的时间是" << (end-start) / CLK_TCK << endl;
return 0;
}
这次显示是3。
然后我们再用所得时间(也就是3)除以循环的次数(5000次)就是代码的运行时间啦。
增大输入数据也可以用来返回有效耗时,如将求第20项改为求100项 求第40项,也可以看出耗时,这种方法比较适合比较两种算法的时耗情况。