计算时间复杂度
常量级
当一段代码中没有循环、递归语句,即使有很多行,时间复杂度依然为常量级O(1)。
void test()
{
int a=1;
int b=2;
a+=b;
}
test()的时间复杂度为O(1)。
不同级——取大头
即只取执行次数最多的那段代码的时间复杂度。
举个最简单的栗子:
void test()
{
int a=1;
for(int i=0;i<n;i++)
a++;
}
在这段代码中,for循环是执行次数最多的一段代码,所以时间复杂度就是O(n)。
再举个栗子:
void test()
{
int a=1,b=1;
for(int i=0;i<n;i++)
a++;
for(int i=0;i<m;i++)
for(int j=0;j<m;j++)
b++;
}
在这段代码中,第一个for循环为O(n),第二个双重循环为O(n2),所以test()的时间复杂度为O(n2)。
同级不同规模——相加
当两段代码同级、但规模不同时,时间复杂度为两者相加。
栗子:
void test()
{
for(int i=0;i<n;i++)
...
for(int i=0;i<m;i++)
...
}
因为无法确定m和n的规模大小,所以时间复杂度为O(m+n)。
若规模相同:
void test()
{
for(int i=0;i<n;i++)
...
for(int i=0;i<n;i++)
...
}
按上述结论,test()时间复杂度是O(2n),但习惯把系数去掉,所以时间复杂度依然是O(n)。
嵌套相乘
如果代码中嵌套函数,则时间复杂度等于两者的乘积。
栗子:
void test01()
{
for(int i=0;i<m;i++)
...
}
void test02()
{
for(int i=0;i<n;i++)
test01();
}
test01的时间复杂度为O(m),test02()的for循环调用了test01,所以test01()的时间复杂度是O(n*m)。
对数级
void test()
{
int i=1;
while(i<n)
i*=2;
}
实际上i的值是一个等比数列。i = 20, 21, 22, …, 2k,由2k < n 得 k < log2n,所以时间复杂度是O(logn)。
测试程序运行时间
clock()
clock()
是一个C++标准库函数,用于计算程序运行时间,返回自进程启动以来所消耗的 CPU 时间。通常用于对程序性能进行简单分析。
该函数的原型如下:
#include <time.h>
clock_t clock(void);
该函数返回从程序启动到调用该函数时所耗费的时钟计时单元数。时钟计时单元数可以使用 CLOCKS_PER_SEC
宏表示。CLOCKS_PER_SEC
是一个标准C库中的常量,表示每秒钟的时钟计时单元数。
需要注意的是,clock()
函数的返回值类型是 clock_t
,通常是一个有符号整数类型。并且使用 clock()
计算程序执行时间的一个缺点是精度较低,可能会受到系统时钟精度和进程切换等因素的影响。
#include<iostream>
using namespace std;
#include <time.h>
void bubbleSort(int a[], int n)
{
for (int i = 0; i < n-1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (a[j] > a[j + 1])
swap(a[j], a[j + 1]);
}
}
}
void check1(int a[],int n)
{
clock_t start = clock();
bubbleSort(a, n);
clock_t end = clock();
double time_taken = (end*1.0 - start) / CLOCKS_PER_SEC;
cout << "clock(): time=" << time_taken*1000 <<" ms"<< endl;
}
int main()
{
int n = 10000;
int a[10000];
for (int i = 0; i < n; i++)a[i] = rand() % n;
check1(a,n);
}
GetTickCount64()
GetTickCount64()
函数是Windows操作系统提供的一个计时函数,它用来获取自系统启动以来的毫秒数。
#include <windows.h>
DWORD64 GetTickCount64(void);
调用GetTickCount64()
函数将返回自系统启动以来的毫秒数,以DWORD64
类型表示。它可以用来测量程序的执行时间,精度通常在几毫秒级别。
需要注意的是,GetTickCount64()
函数的计时是基于系统时钟的,因此受到系统时钟的影响。另外,GetTickCount64()
函数返回的数值是64位的无符号整数,可以用于计算程序运行时间和时间间隔等需要较高精度的计时需求。
#include<iostream>
using namespace std;
#include<windows.h>
void bubbleSort(int a[], int n)
{
for (int i = 0; i < n-1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (a[j] > a[j + 1])
swap(a[j], a[j + 1]);
}
}
}
void check2(int a[], int n)
{
DWORD start, end;
start = GetTickCount64();
bubbleSort(a, n);
end = GetTickCount64();
double time_taken = double(end - start);
cout << "GetTickCount(): time=" << time_taken <<" ms"<< endl;
}
int main()
{
int n = 10000;
int a[10000];
for (int i = 0; i < n; i++)a[i] = rand() % n;
check2(a, n);
}
QueryPerformanceFrequency()
QueryPerformanceFrequency
是Windows下的一个计时函数,它用来获取计时器每秒的计数值。对于大约4秒左右的计时,可以使用QueryPerformanceFrequency
实现足够高的精度。
该函数的原型如下:
#include <windows.h>
BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
调用该函数会返回一个 BOOL 值,表示调用是否成功,返回值为零表示调用失败,非零表示调用成功。
如果调用成功,则参数 lpFrequency
将会被设置为计时器每秒的计数值。此后,我们可以在运行程序之前通过调用 QueryPerformanceCounter
函数获取计时器的当前计数值,运行完程序后再次调用该函数获取最终计数值,将两者相减,就可以得到程序的运行时间。
需要注意的是,使用 QueryPerformanceFrequency
可以提供高精度的计时,不同机器上得到的值可能不同。同时,这个函数的返回值也可以用于计算时间单位。
#include<iostream>
using namespace std;
#include<windows.h>
void bubbleSort(int a[], int n)
{
for (int i = 0; i < n-1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (a[j] > a[j + 1])
swap(a[j], a[j + 1]);
}
}
}
void check3(int a[],int n)
{
LARGE_INTEGER start, end, frequency;
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&start);
bubbleSort(a, n);
QueryPerformanceCounter(&end);
double time_taken = double(end.QuadPart - start.QuadPart) / frequency.QuadPart;
cout << "QueryPerformanceCounter(): time=" << time_taken*1000 << " ms" << endl;
}
int main()
{
int n = 10000;
int a[10000];
for (int i = 0; i < n; i++)a[i] = rand() % n;
check3(a, n);
}
chono
chrono
是 C++ 标准库中提供的时间库,用于进行高精度的时间测量和计时。它提供了更加灵活和具有可移植性的方式来测量时间,适用于各种时间计算和性能分析的需求。
chrono 定义了多个类和函数,其中最常用的是 std::chrono::high_resolution_clock
和 std::chrono::duration
。
std::chrono::high_resolution_clock
是一个高精度时钟类,它提供了更高的精度和稳定性,可以用于精确测量时间间隔。可以通过 now() 成员函数获取当前的时刻。
std::chrono::duration
是一个表示时间间隔的类模板,用于表示一段时间的长度。它提供了方便的方法来进行时间单位转换和计算。通过使用 std::chrono::duration_cast
函数,可以将时间间隔转换为所需的时间单位。
例如,可以使用 std::chrono::high_resolution_clock::now()
获取当前时刻,并将其存储为变量 start
。然后执行某些操作后,再使用 std::chrono::high_resolution_clock::now()
获取当前时刻,并将其存储为变量end
。通过计算end - start
,可以获得两个时刻之间经过的时间间隔。
std::chrono
提供了一种可移植且精确的方法来测量时间,尤其适用于性能分析、计时器和其他时间相关的任务。
#include<iostream>
using namespace std;
#include<chrono>
void bubbleSort(int a[], int n)
{
for (int i = 0; i < n-1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (a[j] > a[j + 1])
swap(a[j], a[j + 1]);
}
}
}
void check4(int a[], int n)
{
std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
bubbleSort(a, n);
std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> duration = std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
cout << "chrono: time=" << duration.count()*1000 << " ms" << endl;
}
int main()
{
int n = 10000;
int a[10000];
for (int i = 0; i < n; i++)a[i] = rand() % n;
check4(a, n);
}