第3课:算法复杂度分析(下):最好、最坏、平均、均摊时间复杂度

最好、最坏时间复杂度

我们先看一个例子:

/*
 例1:查找x在数组中出现的位置,如果没有找到,返回-1。n表示数组array的长度
*/
int findIndex(int[] array, int n, int x) {
  int i = 0;
  int index = -1;
  for (; i < n; ++i) {
    if (array[i] == x) {
       index = i;
       //break; //暂时注释掉此行
    }
  }
  return index;
}

当把break语句注释掉的时候,总是需要遍历整个数组,所以时间复杂度就是数组的长度,为O(n)。
当有break语句的时候,如果找到x,则会提前退出(显然这种写法更高效)。
我们知道x可能出现在数组的任何位置,可能是第一个(时间复杂度为O(1)),可能是最后一个(时间复杂度为O(n)),也可能不存在数组中(时间复杂度为O(n))。

为了表示代码在不同情况下的不同时间复杂度,我们需要引入三个概念:
最好情况时间复杂度、最坏情况时间复杂度和平均情况时间复杂度。

最好情况时间复杂度 就是,在最理想的情况下,执行这段代码的时间复杂度。
最坏情况时间复杂度 就是,在最糟糕的情况下,执行这段代码的时间复杂度
最好、最坏都是在对应的都是极端情况下的代码复杂度,发生的概率其实并不大。

平均情况时间复杂度

平均时间复杂是为了更好地表示平均情况下的复杂度。
还是上面例1,结合概率知识,我们知道,要查找的变量x在数组中的位置,有 n+1 种情况:在数组的0~n-1位置中和不在数组中。
我们暂且认为每种情况发生的概率都一样为:1/(n+1)。
每种情况的时间复杂度为:1/(n+1)1、1/(n+1)2、1/(n+1)3...1/(n+1)n、1/(n+1)*n
所以平均时间复杂度为:(所有情况下的时间复杂度的总和)/(总情况数),即:

平均时间复杂度.png

大O表示法中,可以省略掉系数、低阶、常量,所以,得到的平均时间复杂度就是 O(n)。

其实上面的概率并不都是:1/(n+1)。
要查找的变量 x,要么在数组里,要么就不在数组里。
我们假设在数组中与不在数组中的概率都为 1/2。
查找的数据出现在 0~n-1,这 n 个位置的概率也是一样的,为 1/n,则每种情况出现的概率为1/(2n)。
每种情况的时间复杂度为:1/(2n)1、1/(2n)2、1/(2n)3...1/(2n)n
查找的数据不再数组里,则概率为1/2。时间复杂度为:1/2*n。
所以平均时间复杂度为:(所有情况下的时间复杂度的总和)/(总情况数),即:

平均时间复杂度.png

去掉系数和常量,这段代码的加权平均时间复杂度仍为 O(n)。
这个值就是概率论中的 加权平均值,也叫作 期望值,所以平均时间复杂度的全称应该叫 加权平均时间复杂度或者 期望时间复杂度

均摊时间复杂度

均摊时间复杂度,听起来跟平均时间复杂度有点儿像。
对于初学者来说,这两个概念确实非常容易弄混。

/*
 例2:n表示数组长度,count表示数组存储数据的个数
 往数组中添加数据,如果数组满了,则依次打印出来,然后清空数组
*/
int[] array = new int[n];
int count = 0;
void insert(int val) {
        if (count == array.length) {
            for (int i = 0; i < array.length; ++i) {
                System.out.println(array[i]);
            }
            System.out.println(val);
            array = new int[n];
            count = 0;
        } else {
            array[count] = val;
            count++;
        }
}

分析下前面说的三种时间复杂度。
最好:最理想的情况下数组空闲,时间复杂度为O(1)
最差:数组恰好不空闲,时间复杂度是 O(n)
平均:假设数组的长度是 n,根据数据插入的位置的不同,我们可以分为 n 种情况,
每种情况的时间复杂度是 O(1)。除此之外,还有一种“额外”的情况,就是在数组没有空间时插入一个数据,这个时候的时间复杂度是 O(n)。而且,这 n+1 种情况发生的概率一样,都是 1/(n+1)。所以,根据加权平均的计算方法,我们求得的平均时间复杂度就是:

平均时间复杂度.png

其实平均复杂度分析其实并不需要这么复杂,不需要引入概率论的知识。
相对例1的findIndex()函数:findIndex()函数在极端情况下,复杂度才为 O(1)。
但 insert() 在大部分情况下,时间复杂度都为 O(1)。只有个别情况下复杂度才为 O(n)
不知道你有没有注意到,对于 insert() 函数来说,O(1) 时间复杂度的插入和 O(n) 时间复杂度的插入,
出现的频率是非常有规律的,而且有一定的前后时序关系,一般都是一个 O(n) 插入之后,紧跟着n个 O(1) 的插入操作,循环往复。
针对这样一种特殊场景的复杂度分析,我们并不需要像之前讲平均复杂度分析方法那样,找出所有的输入情况及相应的发生概率,然后再计算加权平均值。
而是用一种更加简单的分析方法:摊还分析法,通过摊还分析得到的时间复杂度我们起了一个名字,叫均摊时间复杂度

那究竟如何使用摊还分析法来分析算法的均摊时间复杂度呢?
每一次 O(n) 的插入操作,都会跟着 n次 O(1) 的插入操作,
所以把耗时多的那次操作均摊到接下来的 n 次耗时少的操作上,均摊下来,
这一组连续的操作的均摊时间复杂度就是 O(1)。这就是均摊分析的大致思路。

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

小结

  • 同一段代码,在不同输入的情况下,复杂度量级有可能是不一样的。所以有了最好、最坏、平均、均摊时间复杂度。
  • 其中最好、最坏情况下的时间复杂度分析起来比较简单。平均、均摊两个复杂度分析相对比较复杂。
  • 在大多数情况下,我们并不需要区分最好、最坏、平均情况时间复杂度三种情况。很多时候,我们使用一个复杂度就可以满足需求了。只有同一块代码在不同的情况下,时间复杂度有量级的差距,我们才会使用这三种复杂度表示法来区分。
  • 平均复杂度只在某些特殊情况下才会用到,而均摊时间复杂度应用的场景比它更加特殊、更加有限。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342