文章目录
时间复杂度概念及意义
在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。实际上一个算法执行所耗费的时间,是不能人为算出来的。我们在这里就是将算法中的基本操作的执行次数,认为是算法的时间复杂度。
时间复杂度是用来判断一个算法的好坏,效率的高低。
时间复杂度的表示
时间复杂度是用大O的渐进表示法来表示(大O符号:是用于描述函数渐进行为的数学符号)。
推导大O阶方法:
- 用常数1取代运行时间中的所有加法常数。
解释:该算法不随输入规模变化。例:直接赋值或有固定循环等。
- 在修改后的运行次数函数中,只保留最高阶项。
解释:假设某个算法的执行次数是F(N)=N^2+N。因为只保留最高项所以把N给删掉,即时间复杂度为O(N^2)。
为什么要删N呢?因为我们就只是要一个大概。CPU每秒可以执行上亿次指令,在CPU看来这个N就可以忽略不计。就好像你有一个亿,你弄丢1万块一样。
- 如果最高阶项存在且不是1,则去除与这个项目相乘的常数。
解释:假设某个算法的执行次数是F(N)=2N。在这里要把2给删掉,即时间复杂度为O(N)。
理由同上。
常见时间复杂度的表示方法
这是它们的运行效率:
O(1) < O(logN) < O(N) < O(N^2) < O(2^N)(越往右越低)。
O(1)
常数时间复杂度
int Add(int count)
{
for (int i = 0; i < 10; i++)
{
count++;
}
return count;
}
由于该算法不随输入规模变化,所以是O(1)。
O(logN)
对数时间复杂度
最典型的就是二分法,二分法是用来查找数据。
//二分法
bool Bisection(int* arr, int key)
{
int left = 0;
int right = sizeof(arr) / sizeof(arr[0]) - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (key > arr[mid])
{
left = mid + 1;
}
else if (key < arr[mid])
{
right = mid - 1;
}
else
{
return true;
}
}
return false;
}
这个要分情况
- 最好第一次就找到
- 能找到
- 最坏没找到
只要是算时间复杂度时存在不同情况,那就一律都按最坏情况来算。
二分法每查找一次就会减少一半的数据,所以可以列出N/2/2/2...=1。
假设运行了x次则2^x=N,即x=logN。大家可能注意到了底数为什么不写2,实际上2是最常见的可以不写,但如果是其它底数就要写。
O(N)
线性时间复杂度
int Addt(int n, int count)
{
for (int i = 0; i < n; i++)
{
count++;
}
return count;
}
时间复杂度随N的增大而线性增加,一般是在单层循环中。
O(N^2)
平方时间复杂度
int Add(int n, int count)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
count++;
}
}
return count;
}
一般是在双层循环中,像冒泡排序等。
O(2^N)
指数时间复杂度
这种在实际中几乎不存在意义,切记在现实中不要写指数时间复杂度。最典型的例子就是斐波那契数列用递归解决。
//斐波那契数列
long long Fib(size_t N)
{
if (N < 3)
return 1;
return Fib(N - 1) + Fib(N - 2);
}
大家咋一看可能看不出来什么,下面我为大家画了个图,方便大家理解。
准确的说它并不是O(2^N),但是我们就只是要一个大概。
好了讲到这儿就差不多讲完了,希望你能有所收获。如果有错误的地方请及时指出,有什么不懂的地方可以私信我哈。