【数据结构】时间复杂度与测试程序运行时间

计算时间复杂度

常量级

当一段代码中没有循环、递归语句,即使有很多行,时间复杂度依然为常量级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_clockstd::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);
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值