目录
数据结构与算法之美(时间复杂度分析)
前言:
数据结构和算法本身解决的是“快”和“省”的问题,即如何让代码运行得更快,如何让代码更省存储空间。所以,执行效率是算法一个非常重要的考量指标。
今天的内容主要围绕:时间复杂度和空间复杂度来讲(空间复杂度没什么好说的 看开辟的空间就行了)
一、什么是复杂度分析?
1.数据结构和算法解决是“如何让计算机更快时间、更省空间的解决问题”。
2.因此需从执行时间和占用空间两个维度来评估数据结构和算法的性能。
3.分别用时间复杂度和空间复杂度两个概念来描述性能问题,二者统称为复杂度。
4.复杂度描述的是算法执行时间(或占用空间)与数据规模的增长关系。
二、为什么要进行复杂度分析?
1.和性能测试相比,复杂度分析有不依赖执行环境、成本低、效率高、易操作、指导性强的特点。
2.掌握复杂度分析,将能编写出性能更优的代码,有利于降低系统开发和维护成本。
大O表示法(大家自己去了解一下)https://baike.baidu.com/item/%E5%A4%A7O%E8%A1%A8%E7%A4%BA%E6%B3%95/1851162
它的作用:
说白了就是让你对这个算法(这段代码)的 运行时间或所需空间 有个大概的概念(知道它的大小罢了)
三、如何分析时间复杂度分析
1)单段代码取频高
看执行频率最高的几行代码(例如while,for循环)【关注循环执行次数最多的那一段代码】
2)多段代码取最大的
什么是最大,也就是说 一段代码可能存在多重循环或者单循环 那么看那个大就是那个(多重循环)。
区别下面的4 这个是指同一个变量 第四点是不同的变量 所以采用加法法则
3)嵌套代码取乘积(乘法法则)
void text(int n,int m) {
int i,j;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{
//待执行的代码
}
}
当前代码的时间复杂度就是 O(n*m)
4)多个规模求加法取二者和(加法法则)
void text(int m, int n) {
int sum1 = 0;
for ( int i = 1; i < m; ++i) {
sum1 = sum1 + i;
}
int sum2 = 0;
for (int j = 1; j < n; ++j) {
sum2 = sum2 + j;
}
}
方法有两个参数控制两个循环的次数,那么这时就取二者复杂度相加。O(m+n)
四、常用的复杂度级别
以上这些复杂度量级 可分为 俩部分 多项式量级和非多项式量级
多项式量级:
O(1)(常数阶)、O(logn)(对数阶)、O(n)(线性阶)、O(nlogn)(线性对数阶)、O(n^2)(平方阶)、O(n^3)(立方阶)
非多项式量级:
O(2^n)(指数阶)、O(n!)(阶乘阶)
这里值得一提的是
多项式阶:它随着数据规模的增长,算法的执行时间和空间占用,按照多项式的比例增长。
非多项式阶:它随着数据规模的增长,算法的执行时间和空间占用暴增,这类算法性能极差。
五、如何掌握复杂度分析
废话来了(多练 练就完事了)
六、复杂度的4个概念
1)最好情况时间复杂度
代码在最理想情况下执行的时间复杂度。
2)最差情况时间复杂度
代码在最坏情况下执行的时间复杂度。
3)平均情况时间复杂度
用代码在所有情况下执行的次数的加权平均值表示。
4)均摊情况时间复杂度
在代码执行的所有复杂度情况中绝大部分是低级别的复杂度,个别情况是高级别复杂度且发生具有时序关系时,可以将个别高级别复杂度均摊到低级别复杂度上。基本上均摊结果就等于低级别复杂度。
// array表示一个长度为n的数组
// 代码中的array.length就等于n
int[] array = new int[n];
int count = 0;
void insert(int val) {
if (count == array.length) {
int sum = 0;
for (int i = 0; i < array.length; ++i) {
sum = sum + array[i];
}
array[0] = sum;
count = 1;
}
array[count] = val;
++count;
}
例子:
每一次O(n)的插入操作,都会跟着n-1次O(1)的插入操作,所以把耗时多的那次操作均摊到接下来的n-1次耗时少的操作上,均摊下来,这一组连续的操作的均摊时间复杂度就是O(1)。
说完这四个概念后 可能有人会问 为什么又这四个 概念了
这是因为同一段代码,在不同输入的情况下,复杂度量级有可能是不一样的。 四个概念是为了更准确的描述对应的时间复杂度。
最重要的是 我们怎么去分析:
最优最差就不提了。
平均情况时间复杂度:
代码在不同情况下复杂度出现量级差别,则用代码所有可能情况下执行次数的加权平均值表示
均摊情况时间复杂度:
对一个数据结构进行一组连续操作中,大部分情况下时间复杂度都很低,只有个别情况下时间复杂度比较高,而且这些操作之间存在前后连贯的时序关系,这个时候,我们就可以将这一组操作放在一块儿分析,看是否能将较高时间复杂度那次操作的耗时,平摊到其他那些时间复杂度比较低的操作上。而且,在能够应用均摊时间复杂度分析的场合,一般均摊时间复杂度就等于最好情况时间复杂度。