1. 什么是时间复杂度?
时间复杂度用来衡量算法的运行速度,具体表示一个算法的基本操作的执行次数。
2. 为什么不用算法的执行时间来表示时间复杂度?
由于不同的硬件平台具有不同的硬件性能,同一个算法在不同的硬件平台上运行时间可能有很大的差异,但是执行次数不会因为硬件性能的改变而变化,所以使用执行次数而不是执行时间来表示算法复杂度更加通用。
3. 如何计算时间复杂度?
时间复杂度采用O()表示,比如一个算法执行N次,则时间复杂度为O(N)。时间复杂度是一个估算值,其表示的是一个量级。比如执行N次,N+1次,2N次,时间复杂度都为O(N)。执行常数次,时间复杂度为O(1)。
时间复杂度示例:
1. 计算Func2的时间复杂度?
void Func2(int N)
{
int count = 0;
for (int k = 0; k < 2 * N ; ++ k)
{
++count;
}
int M = 10;
while (M--)
{
++count;
}
printf("%d\n", count);
}
函数执行次数为2N+10,其时间复杂度为O(N)。系数2和常数10可以忽略,因为它们不影响量级。
2. 计算Fun3的时间复杂度?
void Func3(int N, int M)
{
int count = 0;
for (int k = 0; k < M; ++ k)
{
++count;
}
for (int k = 0; k < N ; ++ k)
{
++count;
}
printf("%d\n", count);
}
函数执行次数为M+N,在不清楚M和N的量级关系的情况下,时间复杂度为O(M+N);如果M和N同一量级,则时间复杂度为O(M)或O(N);如果N的量级大于M,则时间复杂度为O(N);若M的量级大于N的量级则时间复杂度为O(M)。
3. 计算Fun4的时间复杂度?
void Func4(int N)
{
int count = 0;
for (int k = 0; k < 100; ++ k)
{
++count;
}
printf("%d\n", count);
}
函数执行次数为100次,是一个常数值,则时间复杂度为O(1)。
4. 计算二分查找的时间复杂度?
int BinarySearch(int* a, int n, int x)
{
assert(a);
int begin = 0;
int end = n-1;
// [begin, end]:begin和end是左闭右闭区间,因此有=号
while (begin <= end)
{
int mid = begin + ((end-begin)>>1);
if (a[mid] < x)
begin = mid+1;
else if (a[mid] > x)
end = mid-1;
else
return mid;
}
return -1;
}
在一些执行次数不确定的算法中,比如查找算法,由于被查找的个体在所有个体中顺序的不同,算法每次查找的执行次数也不同。这种情况下,采用最大的执行次数来计算时间复杂度。
二分查找最坏的情况是查找到只有最后一个数字时是需要查找的数字。假设一共有N个数字,查找一次则过滤掉一半的数字,即N/2,假设算法一共查找X次,此时只剩下一个数字,即被查找的数字,算数表达式为N/(2^X)=1。可以算出X=logN,对数函数的底为2,这种情况可以省去。时间复杂度为O(logN)。