数据结构与算法之美(一):复杂度分析

本章内容源于笔者对极客时间《数据结构与算法之美》以下章节的学习笔记:

复杂度分析是整个算法学习的精髓,只要掌握了它,数据结构和算法的内容基本上就掌握了一半。

为什么需要复杂度分析

把代码跑一遍,通过统计、监控得到算法执行的时间和占用的内存大小,这种方法称为事后统计法,有非常大的局限性:

  • 1.测试结果非常依赖测试环境
  • 2.测试结果受数据规模的影响很大

我们需要一个不用关心的宿主环境、不用具体的测试数据来测试,就可以粗略地估计算法的执行效率的方法。就是时间、空间复杂度分析法。

大O复杂度表示法

假设每行代码执行的时间都一样,为单位时间,所有代码的执行时间T(n)与每行代码的执行次数成正比。我们把这个规律总结成一个公式:T(n) = O(f(n))

  • T(n)表示代码执行的时间
  • f(n)表示每行代码执行的次数总和
  • n表示数据规模的大小

这就是大O时间复杂度表示法

  • 注意:大O时间复杂度实际上并不代表真正的执行时间,表示代码执行时间随数据规模增长的变化趋势。公式中的低阶、常量、系数三部分并不左右增长趋势,所以忽略。

时间复杂度分析

时间复杂度全称渐进时间复杂度。分析技巧如下:

  • 1.只关注循环执行次数最多的一段代码
  • 2.加法法则:总复杂度等于量级最大的那段代码的复杂度
  • 3.乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积

强调一下,即便一段段代码循环10000次、100000次,只要是一个已知的数,跟n无关,照样也是常量级的执行时间。当n无限大的时候,就可以忽略。

以上三种复杂度的分析技巧不用刻意去记忆,实际上,复杂度分析这个东西关键在于“熟练”,多看案例多分析。

几种常见时间复杂度实例分析

常见复杂度量级并不多,以下几乎涵盖了今后接触的所有代码的复杂度量级。

复杂度量级 大O表达式 所属分类
常量阶 O(1) 多项式量级
对数阶 O(logn) 多项式量级
线性阶 O(n) 多项式量级
线性对数阶 O(nlogn) 多项式量级
平方阶 O(n2) 多项式量级
立方阶 O(n3) 多项式量级
k次方阶 O(nk) 多项式量级
指数阶 O(2n) 非多项式量级
阶乘阶 O(n!) 非多项式量级

O(1)

只要代码的执行时间不随n的增大而增长,时间复杂度都记作O(1)。一般情况下,只要算法中不存在循环语句、递归语句,即使有成千上万行的代码,其时间复杂度也是Ο(1)

O(logn)、O(nlog)

对数阶时间复杂度非常常见,同时也是最难分析的一种时间复杂度。

i = 1;
while (i <= n) {
    i = i * 2;
}

以上代码中可以看出,变量i的值从1开始取,每循环一次就乘以 2,当大于n时,循环结束。i的取值是一个等比数列,求解2x = n,x = log2n。

类似的,log3n = log32 * log2n,不管是以2、3甚至是10为底,都可以转换为c * log2n,忽略系数和对数的“底”,都记作O(logn)

如果一段代码的时间复杂度是 O(logn) ,循环执行n遍,时间复杂度就是 O(nlogn) 了。

O(nlogn) 也是一种非常常见的算法时间复杂度。比如,归并排序、快速排序的时间复杂度都是 O(nlogn)

O(m+n)、O(m*n)

代码的复杂度由两个数据的规模来决定。

空间复杂度分析

空间复杂度全称渐进空间复杂度,表示算法的存储空间与数据规模之间的增长关系

空间复杂度分析比时间复杂度分析要简单很多。常见的空间复杂度就是O(1)O(n)O(n2),像 O(logn)O(nlogn) 这样的对数阶复杂度平时都用不到。

小结:复杂度包括时间复杂度和空间复杂度,用来分析算法执行效率与数据规模之间的增长关系。越高阶复杂度的算法执行效率越低。常见复杂度从低阶到高阶有:
O(1)O(logn)O(n)O(nlogn)O(n2 )

复杂度分析的4个概念

  • 最好情况时间复杂度:代码在最理想情况下执行的时间复杂度。
  • 最坏情况时间复杂度:代码在最糟糕情况下执行的时间复杂度。
  • 平均情况时间复杂度:引入概率的概念,代码在所有情况下执行的次数的加权平均值。

实际上,在大多数情况下并不需要区分最好、最坏、平均情况时间复杂度。只有同一块代码在不同的情况下,时间复杂度有量级的差距,才会使用这三种复杂度表示法来区分。

  • 均摊时间复杂度:利用摊还分析法将个别情况的高复杂度均摊到大部分情况的低复杂度所得到的时间复杂度。

应用场景:对一个数据结构进行一组连续操作中,大部分情况下时间复杂度都很低,只有个别情况下时间复杂度比较高,而且这些操作之间存在前后连贯的时序关系,这个时候就可以将这一组操作放在一块儿分析,看是否能将较高时间复杂度那次操作的耗时,平摊到其他那些时间复杂度比较低的操作上。

  • 一般均摊时间复杂度就等于最好情况时间复杂度。
  • 均摊时间复杂度就是一种特殊的平均时间复杂度。

小结:引入最好情况时间复杂度、最坏情况时间复杂度、平均情况时间复杂度、均摊时间复杂度这几个概念是因为同一段代码在不同输入情况下,复杂度量级有可能不一样,通过比较分析,我们可以更加全面地表示一段代码的执行效率。

思考题一:有人说,我们项目之前都会进行性能测试,再做代码的时间复杂度、空间复杂度分析,是不是多此一举呢?而且,每段代码都分析一下时间复杂度、空间复杂度,是不是很浪费时间呢?你怎么看待这个问题呢?

参考回答

  • 1.复杂度分析是一个理论分析,与宿主无关,能让程序员在写代码时对算法的执行效率有个大致认识,从而写出效率更高的程序;
  • 2.通过练习就能达到熟练地看出是否浪费时间,比如复杂度越低阶效率越高,为代码质量考虑并不算浪费时间。

思考题二:分析下面这个 add() 函数的时间复杂度。

// 全局变量,大小为 10 的数组 array,长度 len,下标 i
int array[] = new int[10]; 
int len = 10;
int i = 0;

// 往数组中添加一个元素
void add(int element) {
   if (i >= len) { // 数组空间不够了
     // 重新申请一个2倍大小的数组空间
     int new_array[] = new int[len*2];
     // 把原来array数组中的数据依次copy到new_array
     for (int j = 0; j < len; ++j) {
       new_array[j] = array[j];
     }
     // new_array 复制给 array,array 现在大小就是 2 倍 len 了
     array = new_array;
     len = 2 * len;
   }
   // 将 element 放到下标为 i 的位置,下标 i 加一
   array[i] = element;
   ++i;
}

参考回答

以上代码实现往一个数组中添加数据,要是数组放不下了就将数组扩大到原来2倍,然后再添加新元素。最坏情况时间复杂度是 O(n),最好情况时间复杂度、平均情况时间复杂度、均摊时间复杂度都是 O(1)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容