时间复杂度和空间复杂度总结
1.算法效率
算法效率分两种,时间效率和空间效率,即时间复杂度和空间复杂度,前者衡量算法运行速度,后者衡量算法所需要的额外空间
2.时间复杂度
2.1基本概念
算法中的时间复杂度是一个函数,定量描述了算法运行时间
总结下来就是:算法种基本操作的执行次数
关注点:操作的数量级/基本操作的执行次数
①执行时间和硬件资源强相关,不同硬件处理速度有差异
②CPU每秒钟执行操作在亿级以上
2.2大O的渐进表示法
// 请计算一下Func1基本操作执行了多少次?
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);
}
//Func1 执行的基本操作次数 :
N = 10 F(N) = 130
N = 100 F(N) = 10210
N = 1000 F(N) = 1002010
实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这里我们使用大O的渐进表示法。
大O符号(Big O notation):是用于描述函数渐进行为的数学符号。
推导大O阶方法:
1、最高次项有系数,忽略系数
2、如果执行次数为常数次,就为O(1)
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。
4.不能依靠循环的嵌套简单腿断时间复杂度,应该具体分析基本操作的执行次数
使用大O的渐进表示法以后,Func1的时间复杂度为:O(n²)
N = 10 F(N) = 100
N = 100 F(N) = 10000
N = 1000 F(N) = 1000000
通过上面我们会发现大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。
另外有些算法的时间复杂度存在最好、平均和最坏情况:
最坏情况:任意输入规模的最大运行次数(上界)
平均情况:任意输入规模的期望运行次数
最好情况:任意输入规模的最小运行次数(下界)
例如:在一个长度为N数组中搜索一个数据x
最好情况:1次找到
最坏情况:N次找到
平均情况: N/2次找到
3.空间复杂度
官方概念:是对一个算法在运行过程中临时占用存储空间大小的亮度
直白来说:空间复杂度不看程序占用多少B的内存,直接看变量的个数,并且是算法中创建的变量个数
具体实例
// 计算BubbleSort的空间复杂度?
void BubbleSort(int* a, int n) {
assert(a);
for (size_t end = n; end > 0; --end)
{
int exchange = 0;
for (size_t i = 1; i < end; ++i)
{
if (a[i-1] > a[i])
{
Swap(&a[i-1], &a[i]);
exchange = 1;
}
}
if (exchange == 0)
break;
}
}
使用常数个额外空间,所以空间复杂度为O(1)
如果算法执行所需要的临时空间不随着某个变量n的大小而变化,所以空间复杂度为一个常量!,可表示为O(1)
// 计算阶乘递归Factorial的空间复杂度?
long long Factorial(size_t N) {
return N < 2 ? N : Factorial(N-1)*N; }
递归调用了N次,开辟了N个栈帧,每个栈帧使用了常数个空间,空间复杂度为O(n)