时间复杂度(大O)

什么是大O?

n 表示数据规模,O(f(n))表示运行算法所需要执行的指令数,和 f(n) 成正比。举例如下:

算法时间复杂度所需指令数
二分查找法 O(logn) a×logn
数组最大/小值 O(n) b×n
归并排序法 O(nlogn) c×nlogn
选择排序法 O(n2) d×n2

需要注意的是,学术界定义的大O为 O(f(n)) 表示算法执行的上界,而在业界我们一般认为:

O(f(n)) 表示算法执行的最低上界

例题:

一个字符串数组,将数组中每一个字符串按照字母序排序;之后再将整个字符串按照字典序排序,时间复杂度是多少?

设字符串数组中最长字符串长度为 s ,整个有n个字符串。分两步来看:

1)每个字符串排序需要 O(slogs) ,一共 n 个字符串,也就是需要O(nslogs)
2)对排好序的n个字符串进行字典序排序,需要比较 O(nlogn) 次,两个字符串之间进行比较需要进行 O(s) ,总体来说就需要 O(snlogn)
综上,需要的时间复杂度为:

O(nslogs+snlogn)=O(ns(logs+logn))

需要注意的

算法复杂度是和用例相关,比如插入排序最差情况是 O(n2) ,最好情况是 O(n) ,业界说的时间复杂度是针对平均情况来说的,也即是 O(n2)

数据规模

在I7-7700HQ上测试如下代码:

#include <iostream>
#include <cmath>
#include <ctime>

using namespace std;

int main(){


    for (int x = 1; x <= 9; x++){
        int n = pow(10,x);

        clock_t startTime = clock();

        int sum = 0;
        for (int i = 0; i < n; i++){
            sum += i;
        }

        clock_t endTime = clock();

        cout << "10^" << x << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s" << endl;

    }

    system("pause");
    return 0;
}

运行结果如下:


这里写图片描述

也就是说,如果想在1s之类解决问题:

时间复杂度可以处理的数据规模
O(n) 108
O(nlogn) 107
O(n2) 104

保守估计下,可以再对数据规模除以10。

空间复杂度

总体来讲,就是多开了一个辅助的数组: O(n) ,多开了一个辅助的二维数组: O(n2) ;多开常数空间: O(1) 。需要注意的是,

递归调用是有空间代价的

这里写图片描述

也就是,递归的深度是多少,所开的空间复杂度就是多少。

时间复杂度分析的一些例题


这里写图片描述

看到是双层循环,不一定都是 O(n2) 级别的算法,请看下例:

这里写图片描述

再如下例,时间复杂度为 O(nlogn)

这里写图片描述

再有,其他的一些情况:

这里写图片描述

这里写图片描述

这里写图片描述

为什么算法复杂度为 O(logn) 级别时,我们不关注 log 的底是多少?


这里写图片描述

因为不同的底之间,只是相差了一个常数,所以都是在一个量级上的,都称为 O(logn)

上述时间复杂度的分析的重点在于,分析与数据规模有关系的那一部分的基本操作

递归中的时间复杂度分析

1、递归中进行一次递归调用,递归深度为depth,每个递归中时间复杂度为T,则总的时间复杂度为 O(T×depth) ,比如下面的例子:

1)在二分搜索中,递归深度为 logn

这里写图片描述

2)0到n的求和中,递归深度为 n

这里写图片描述

3)求x的n次方时,递归深度为logn

这里写图片描述

2、递归中进行多次递归调用,应关注递归调用的次数,可以画出一个递归树来观察

这里写图片描述

n=3 时,调用了
1+2+4+8=15

n 次时需要调用
20+21+22+23+...+2n=2n+11

均摊复杂度分析

在vector实现中,当push_back时当前动态数组容量不够时,需要重新开辟新的空间(也就是resize操作,这个过程的时间复杂度为 O(n) ),由于均摊到每一步,使得push_back操作的时间复杂度仍然是 O(1) ,也就是常数级别的,分析过程如下。

这里写图片描述

解决复杂度震荡,在pop_back操作中,当元素个数为容量的 14 时,进行resize操作,且resize操作的大小为当前容量的 12

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值