C语言程序的运行速度测试
代码随想录上提到了一点,即我们应该学会估计一个时间复杂度较高的算法,在机器上的运行速度。
- 如果题目给出的数据量级在高复杂度的算法中会超时,那就应该放弃使用这个代码,而想其他时间复杂度更优的解法;
- 这样能避免在刷题的时候,图简单写了个暴力写法却发现超时不过的尴尬(没错说的就是我自己)
大部分OJ题目,对C/C++代码的时间限制都是1s。所以我们测试的目标也将放在1s上。

1.代码
来源:http://www.360doc.com/content/23/0119/15/2690044_1064211133.shtml
我的Git:Gitee
1.1 循环
首先是func.h,内部包含了三个循环函数,时间复杂度分别为O(N) O(N^2) O(NlogN)
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 
 | #include <stdio.h>
 
 void func1(long long n)
 {
 printf("开始执行O(N)的函数:%lld\n",n);
 long long k=0;
 for(long long i=0;i<n;i++)
 {
 k++;
 }
 }
 
 void func2(long long n)
 {
 printf("开始执行O(N^2)的函数:%lld\n",n);
 long long k=0;
 for(long long i=0;i<n;i++)
 {
 for(long long j=0;j<n;j++)
 {
 k++;
 }
 }
 }
 
 
 void func3(long long n)
 {
 printf("开始执行O(NlogN)的函数:%lld\n",n);
 long long k=0;
 for(long long i=0;i<n;i++)
 {
 
 for(long long j=1;j<n;j*=2)
 {
 k++;
 }
 }
 }
 
 | 
1.2 获取毫秒级时间戳
随后是主文件,这里我们需要进行时间的测试,所以得想办法获取到毫秒级的时间戳。
time.h中的time函数只能够返回秒级时间戳,对于代码的时间测试来说显然是不够的。我们需要借助Windows和Linux的系统函数,获取到毫秒级时间戳
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 
 | #define _CRT_SECURE_NO_WARNINGS 1#include <stdint.h>
 #include <stdio.h>
 
 
 #ifdef _WIN32
 #include<time.h>
 #include<windows.h>
 #else
 #include <sys/time.h>
 #include <unistd.h>
 #endif
 
 
 
 uint64_t GetCurrentTimerMS(char* szTimer)
 {
 uint64_t nTimer = 0;
 #ifdef _WIN32
 SYSTEMTIME currentTime;
 GetLocalTime(¤tTime);
 struct tm temptm = { currentTime.wSecond,
 currentTime.wMinute,
 currentTime.wHour,
 currentTime.wDay,
 currentTime.wMonth - 1,
 currentTime.wYear - 1900
 };
 nTimer =  mktime(&temptm) * 1000 + currentTime.wMilliseconds;
 #else
 struct timeval tv;
 gettimeofday(&tv,NULL);
 
 nTimer = tv.tv_sec*1000 + tv.tv_usec/1000;
 #endif
 if(szTimer != NULL)
 sprintf(szTimer, "%llu", nTimer);
 return nTimer;
 }
 
 int test_def()
 {
 char szTimer[64];
 uint64_t nTimer=-1;
 GetCurrentTimerMS(szTimer);
 nTimer = GetCurrentTimerMS(NULL);
 printf("millisecond1:%s\nmillisecond2:%llu\n",szTimer,nTimer );
 return 0;
 }
 
 | 
1.3 获取时间戳测试
先来执行一下这个测试函数test_def,结果如下
| 12
 3
 4
 
 | $ gcc test.c -o test$ ./test
 millisecond1:1681878963361
 millisecond2:1681878963361
 
 | 
成功打印出了毫秒级的时间戳,分别是字符串类型和uint64_t长整型
| 12
 3
 4
 5
 6
 7
 
 | #ifdef _WIN32#include <time.h>
 #include<windows.h>
 #else
 #include <sys/time.h>
 #include <unistd.h>
 #endif
 
 | 
这里还采用了宏定义,自动判断windows还是linux,调用各自的系统接口函数。
如下图,在Windows下的Vs2019也成功执行这个函数

2.开始测试
这个命令可以查看linux下的cpu型号
| 12
 
 | $ cat /proc/cpuinfo | grep 'model name' |uniqmodel name      : Intel(R) Celeron(R) N5105 @ 2.00GHz
 
 | 
2.1 示例
先测试O(N)算法在何等数量级时会超过1s
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 
 | $ ./test请键入n:500000000
 start_time: 1681880952986
 开始执行O(N)的函数:500000000
 end_time:   1681880954073
 diff:       1087ms
 start_time: 1681880963999
 开始执行O(N)的函数:450000000
 end_time:   1681880964993
 diff:       994ms
 请键入n:460000000
 start_time: 1681881111806
 开始执行O(N)的函数:460000000
 end_time:   1681881112804
 diff:       998ms
 请键入n:470000000
 start_time: 1681881117572
 开始执行O(N)的函数:470000000
 end_time:   1681881118604
 diff:       1032ms
 请键入n:400000000
 start_time: 1681880967163
 开始执行O(N)的函数:400000000
 end_time:   1681880968043
 diff:       880ms
 请键入n:550000000
 start_time: 1681880970538
 开始执行O(N)的函数:550000000
 end_time:   1681880971736
 diff:       1198ms
 
 | 
如上,是我的linux服务器的测试结果。
数量级大概在460000000的时候,就会达到998ms,也就是将近1s
所以,当我们看到Oj的测试用量超过4500000000数量级的时候,就应该放弃O(N)算法!
而在windows下,我的R7 5800H笔记本,运行到700000000数量级的时候,才需要1s
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | 请键入n:500000000start_time: 1681881322528
 开始执行O(N)的函数:500000000
 end_time:   1681881323236
 diff:       708ms
 请键入n:1000000000
 start_time: 1681881327548
 开始执行O(N)的函数:1000000000
 end_time:   1681881328965
 diff:       1417ms
 请键入n:600000000
 start_time: 1681881332928
 开始执行O(N)的函数:600000000
 end_time:   1681881333792
 diff:       864ms
 请键入n:800000000
 start_time: 1681881337404
 开始执行O(N)的函数:800000000
 end_time:   1681881338537
 diff:       1133ms
 请键入n:700000000
 start_time: 1681881341486
 开始执行O(N)的函数:700000000
 end_time:   1681881342486
 diff:       1000ms
 
 | 
2.2 结果
按如上办法测试,我分别测试了三种时间复杂度在多个平台上的结果。稍微了解这些数字,能帮助我们在判断题目选用算法上提供帮助。
表中E8是科学计数法,代表10的8次方
| 平台/CPU | 时间复杂度 | 数量级 | 时间(毫秒) | 
| windows (amd R7-5800H) | O(N) | 7E9 | 1000 | 
|  | O(N2) | 3E4 | 1022 | 
|  | O(NlogN) | 1.7E7 | 996 | 
| Centos8 (Intel N5105) | O(N) | 4.5E8 | 994 | 
|  | O(N2) | 2E4 | 920 | 
|  | O(NlogN) | 1.8E7 | 966 | 
| Centos7.2 (Intel Xeon Platinum 8255C) | O(N) | 5.8E8 | 990 | 
|  | O(N2) | 2.4E4 | 976 | 
|  | O(NlogN) | 2.1E7 | 976 | 
数据测试于23.04.19
本来还想测测牛客和leetcode的,结果发现它们运行O(N^2)量级的函数,都E7了还是几ms就搞定了,感觉测试的结果不准,故放弃😂
