本篇前言
在C语言阶段,我们学过了一些排序和查找算法,冒泡排序,快速排序,二分查找等等,哪种算法更好呢,我们如何衡量一个算法的好坏呢?本篇来学习算法的时间复杂度和空间复杂度,相信学完后你就会明白了。
(1)算法效率
算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源 。因此衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。
时间复杂度主要衡量一个算法的运行快慢,而空间复杂度主要衡量一个算法运行所需要的额外空间。
随着计算机行业的高速发展,计算机储存容量已经达到了很高的程序,已经不需要特别关注一个算法的空间效率了,重点关注其时间复杂度。
(2)时间复杂度的计算
1)什么是时间复杂度
算法中的基本操作的==执行次数==,为算法的时间复杂度。
直接上实例来讲解具体的计算方法吧
//计算Func1中++count语句总共执行了多少次?
void Func1(int N)
{
int count = 0;
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < N; ++j)
{
++count;
}
}
for (int k = 0; k < 2 * N; ++k)
{
++count;
}
int M = 10;
while (M--)
{
++count;
}
printf("%d\n", count);
}
算法执行次数函数表达式:F(N) = N2 + 2 * N + 10
N = 10,F(N) = 130;N = 100,F(N) = 10210;N = 1000,F(N) = 1002010;
通过计算发现,N越大,对结果影响越小,所以在实际计算时间复杂度时,我们并不需要计算精确的执行次数,而只需要计算大概执行次数,使用大O渐进表示法(估算),只保留对结果影响最大的一项。
2)大O渐进表示法(估算)
1、推导大O阶方法:
用常数1取代运行时间中的所有加法常数。
在修改后的运行次数函数中,只保留最高阶项。
如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。
这些方法看起来有些许摸不着头脑哈,我们来举几个例子说明,比如:
- 执行次数函数 F(N) = 10,使用大O渐进表示法后,时间复杂度为:O(1)
- 执行次数函数 F(N) = N2 + 2 * N + 10,使用大O渐进表示法后,时间复杂度为:O(N2)
- 执行次数函数 F(N) = 2 * N + 10,使用大O渐进表示法后,时间复杂度为:O(N)
2、有些算法的时间复杂度存在最好、平均和最坏情况:
最坏情况:任意输入规模的最大运行次数(上界)
平均情况:任意输入规模的期望运行次数
最好情况:任意输入规模的最小运行次数(下界)
例如:在一个长度为 N 数组中搜索一个数据 X
最好情况:1次就找到
最坏情况:N次才找到(一般以最坏情况为准)
平均情况:N/2次找到
而在实际中一般情况关注的是算法的最坏运行情况,是一种保底思维,没有比这更差了哈哈,所以数组中搜索数据时间复杂度为O(N)
3)时间复杂度计算实例
实例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);
}
执行次数函数 F(N) = 2 * N + 10,使用大O渐进表示法后,时间复杂度为