04| 復(fù)雜度分析(下):淺析最好允瞧、最壞简软、平均、均攤時(shí)間復(fù)雜度

04| 復(fù)雜度分析(下):淺析最好述暂、最壞痹升、平均、均攤時(shí)間復(fù)雜度

上一節(jié)畦韭,我們講了復(fù)雜度的大 O 表示法和幾個(gè)分析技巧疼蛾,還舉了一些常見復(fù)雜度分析的例子,比如 O(1) 艺配、 O(logn) 察郁、 O(n) 、 O(nlogn) 復(fù)雜度分析转唉。掌握了這些內(nèi)容皮钠,

對(duì)于復(fù)雜度分析這個(gè)知識(shí)點(diǎn),你已經(jīng)可以到及格線了赠法。但是鳞芙,我想你肯定不會(huì)滿足于此。

今天我會(huì)繼續(xù)給你講四個(gè)復(fù)雜度分析方面的知識(shí)點(diǎn),最好情況時(shí)間復(fù)雜度(best case time complexity)原朝、最壞情況時(shí)間復(fù)雜度(worst case time complexity)驯嘱、平均

情況時(shí)間復(fù)雜度(average case time complexity)、均攤時(shí)間復(fù)雜度(amortized time complexity)喳坠。如果這幾個(gè)概念你都能掌握鞠评,那對(duì)你來說,復(fù)雜度分析這部分內(nèi)

容就沒什么大問題了壕鹉。

最好剃幌、最壞情況時(shí)間復(fù)雜度

上一節(jié)我舉的分析復(fù)雜度的例子都很簡(jiǎn)單,今天我們來看一個(gè)稍微復(fù)雜的晾浴。你可以用我上節(jié)教你的分析技巧负乡,自己先試著分析一下這段代碼的時(shí)間復(fù)雜度。

// n表示數(shù)組array的長(zhǎng)度

int find(int[] array, int n, int x) {

int i = 0;

int pos = -1;

for (; i < n; ++i) {

if (array[i] == x) pos = i;

}

return pos;

}

你應(yīng)該可以看出來脊凰,這段代碼要實(shí)現(xiàn)的功能是抖棘,在一個(gè)無序的數(shù)組( array )中,查找變量 x 出現(xiàn)的位置狸涌。如果沒有找到切省,就返回 -1 。按照上節(jié)課講的分析方法帕胆,這

段代碼的復(fù)雜度是 O(n) 朝捆,其中, n 代表數(shù)組的長(zhǎng)度懒豹。

我們?cè)跀?shù)組中查找一個(gè)數(shù)據(jù)芙盘,并不需要每次都把整個(gè)數(shù)組都遍歷一遍,因?yàn)橛锌赡苤型菊业骄涂梢蕴崆敖Y(jié)束循環(huán)了脸秽。但是儒老,這段代碼寫得不夠高效。我們可以這

樣優(yōu)化一下這段查找代碼豹储。

// n表示數(shù)組array的長(zhǎng)度

int find(int[] array, int n, int x) {

int i = 0;

int pos = -1;

for (; i < n; ++i) {

if (array[i] == x) {

pos = i;

break;

}

}

return pos;

}

這個(gè)時(shí)候贷盲,問題就來了。我們優(yōu)化完之后剥扣,這段代碼的時(shí)間復(fù)雜度還是 O(n) 嗎巩剖?很顯然,咱們上一節(jié)講的分析方法钠怯,解決不了這個(gè)問題佳魔。

因?yàn)椋檎业淖兞?x 可能出現(xiàn)在數(shù)組的任意位置晦炊。如果數(shù)組中第一個(gè)元素正好是要查找的變量 x 鞠鲜,那就不需要繼續(xù)遍歷剩下的 n-1 個(gè)數(shù)據(jù)了宁脊,那時(shí)間復(fù)雜度就

是 O(1) 。但如果數(shù)組中不存在變量 x 贤姆,那我們就需要把整個(gè)數(shù)組都遍歷一遍榆苞,時(shí)間復(fù)雜度就成了 O(n) 。所以霞捡,不同的情況下坐漏,這段代碼的時(shí)間復(fù)雜度是不一樣的。

為了表示代碼在不同情況下的不同時(shí)間復(fù)雜度碧信,我們需要引入三個(gè)概念:最好情況時(shí)間復(fù)雜度赊琳、最壞情況時(shí)間復(fù)雜度和平均情況時(shí)間復(fù)雜度。

顧名思義砰碴,最好情況時(shí)間復(fù)雜度就是躏筏,在最理想的情況下,執(zhí)行這段代碼的時(shí)間復(fù)雜度呈枉。就像我們剛剛講到的趁尼,在最理想的情況下,要查找的變量x正好是數(shù)組的

04|復(fù)雜度分析(下):淺析最好碴卧、最壞弱卡、平均乃正、均攤時(shí)間復(fù)雜度

file:///F/temp/geektime/數(shù)據(jù)結(jié)構(gòu)與算法之美/04復(fù)雜度分析(下):淺析最好住册、最壞、平均瓮具、均攤時(shí)間復(fù)雜度.html[2019/1/15 15:35:12]

第一個(gè)元素荧飞,這個(gè)時(shí)候?qū)?yīng)的時(shí)間復(fù)雜度就是最好情況時(shí)間復(fù)雜度。

同理名党,最壞情況時(shí)間復(fù)雜度就是叹阔,在最糟糕的情況下,執(zhí)行這段代碼的時(shí)間復(fù)雜度传睹。就像剛舉的那個(gè)例子耳幢,如果數(shù)組中沒有要查找的變量x,我們需要把整個(gè)數(shù)組

都遍歷一遍才行欧啤,所以這種最糟糕情況下對(duì)應(yīng)的時(shí)間復(fù)雜度就是最壞情況時(shí)間復(fù)雜度睛藻。

平均情況時(shí)間復(fù)雜度

我們都知道,最好情況時(shí)間復(fù)雜度和最壞情況時(shí)間復(fù)雜度對(duì)應(yīng)的都是極端情況下的代碼復(fù)雜度邢隧,發(fā)生的概率其實(shí)并不大店印。為了更好地表示平均情況下的復(fù)雜度,

我們需要引入另一個(gè)概念:平均情況時(shí)間復(fù)雜度倒慧,后面我簡(jiǎn)稱為平均時(shí)間復(fù)雜度按摘。

平均時(shí)間復(fù)雜度又該怎么分析呢包券?我還是借助剛才查找變量 x 的例子來給你解釋。

要查找的變量x在數(shù)組中的位置炫贤,有n+1種情況:在數(shù)組的0~n-1位置中和不在數(shù)組中溅固。我們把每種情況下,查找需要遍歷的元素個(gè)數(shù)累加起來兰珍,然后再除以n+1发魄,

就可以得到需要遍歷的元素個(gè)數(shù)的平均值,即:


我們知道俩垃,時(shí)間復(fù)雜度的大 O 標(biāo)記法中励幼,可以省略掉系數(shù)、低階口柳、常量苹粟,所以,咱們把剛剛這個(gè)公式簡(jiǎn)化之后跃闹,得到的平均時(shí)間復(fù)雜度就是 O(n) 嵌削。

這個(gè)結(jié)論雖然是正確的,但是計(jì)算過程稍微有點(diǎn)兒?jiǎn)栴}望艺。究竟是什么問題呢苛秕?我們剛講的這 n+1 種情況,出現(xiàn)的概率并不是一樣的找默。我?guī)憔唧w分析一下艇劫。(這里

要稍微用到一點(diǎn)兒概率論的知識(shí),不過非常簡(jiǎn)單惩激,你不用擔(dān)心店煞。)

我們知道,要查找的變量 x 风钻,要么在數(shù)組里顷蟀,要么就不在數(shù)組里。這兩種情況對(duì)應(yīng)的概率統(tǒng)計(jì)起來很麻煩骡技,為了方便你理解鸣个,我們假設(shè)在數(shù)組中與不在數(shù)組中的概

率都為 1/2 。另外布朦,要查找的數(shù)據(jù)出現(xiàn)在 0 ~ n-1 這 n 個(gè)位置的概率也是一樣的囤萤,為 1/n 。所以喝滞,根據(jù)概率乘法法則阁将,要查找的數(shù)據(jù)出現(xiàn)在 0 ~ n-1 中任意位置的概率就

是 1/(2n) 。

因此右遭,前面的推導(dǎo)過程中存在的最大問題就是做盅,沒有將各種情況發(fā)生的概率考慮進(jìn)去缤削。如果我們把每種情況發(fā)生的概率也考慮進(jìn)去,那平均時(shí)間復(fù)雜度的計(jì)算過

程就變成了這樣:


04|復(fù)雜度分析(下):淺析最好吹榴、最壞亭敢、平均、均攤時(shí)間復(fù)雜度

file:///F/temp/geektime/數(shù)據(jù)結(jié)構(gòu)與算法之美/04復(fù)雜度分析(下):淺析最好图筹、最壞帅刀、平均、均攤時(shí)間復(fù)雜度.html[2019/1/15 15:35:12]

這個(gè)值就是概率論中的加權(quán)平均值远剩,也叫作期望值扣溺,所以平均時(shí)間復(fù)雜度的全稱應(yīng)該叫加權(quán)平均時(shí)間復(fù)雜度或者期望時(shí)間復(fù)雜度。

引入概率之后瓜晤,前面那段代碼的加權(quán)平均值為 (3n+1)/4 锥余。用大 O 表示法來表示,去掉系數(shù)和常量痢掠,這段代碼的加權(quán)平均時(shí)間復(fù)雜度仍然是 O(n) 驱犹。

你可能會(huì)說,平均時(shí)間復(fù)雜度分析好復(fù)雜啊足画,還要涉及概率論的知識(shí)雄驹。實(shí)際上,在大多數(shù)情況下淹辞,我們并不需要區(qū)分最好医舆、最壞、平均情況時(shí)間復(fù)雜度三種情

況桑涎。像我們上一節(jié)課舉的那些例子那樣彬向,很多時(shí)候兼贡,我們使用一個(gè)復(fù)雜度就可以滿足需求了攻冷。只有同一塊代碼在不同的情況下,時(shí)間復(fù)雜度有量級(jí)的差距遍希,我們

才會(huì)使用這三種復(fù)雜度表示法來區(qū)分等曼。

均攤時(shí)間復(fù)雜度

到此為止,你應(yīng)該已經(jīng)掌握了算法復(fù)雜度分析的大部分內(nèi)容了凿蒜。下面我要給你講一個(gè)更加高級(jí)的概念禁谦,均攤時(shí)間復(fù)雜度,以及它對(duì)應(yīng)的分析方法废封,攤還分析(或

者叫平攤分析)州泊。

均攤時(shí)間復(fù)雜度,聽起來跟平均時(shí)間復(fù)雜度有點(diǎn)兒像漂洋。對(duì)于初學(xué)者來說遥皂,這兩個(gè)概念確實(shí)非常容易弄混力喷。我前面說了,大部分情況下演训,我們并不需要區(qū)分最好弟孟、

最壞、平均三種復(fù)雜度样悟。平均復(fù)雜度只在某些特殊情況下才會(huì)用到拂募,而均攤時(shí)間復(fù)雜度應(yīng)用的場(chǎng)景比它更加特殊、更加有限窟她。

老規(guī)矩陈症,我還是借助一個(gè)具體的例子來幫助你理解。(當(dāng)然震糖,這個(gè)例子只是我為了方便講解想出來的爬凑,實(shí)際上沒人會(huì)這么寫。)

// array表示一個(gè)長(zhǎng)度為n的數(shù)組

// 代碼中的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;

}

我先來解釋一下這段代碼试伙。這段代碼實(shí)現(xiàn)了一個(gè)往數(shù)組中插入數(shù)據(jù)的功能嘁信。當(dāng)數(shù)組滿了之后,也就是代碼中的 count == array.length 時(shí)疏叨,我們用 for 循環(huán)遍歷數(shù)組求

04|復(fù)雜度分析(下):淺析最好潘靖、最壞、平均蚤蔓、均攤時(shí)間復(fù)雜度

file:///F/temp/geektime/數(shù)據(jù)結(jié)構(gòu)與算法之美/04復(fù)雜度分析(下):淺析最好卦溢、最壞、平均秀又、均攤時(shí)間復(fù)雜度.html[2019/1/15 15:35:12]

和单寂,并清空數(shù)組,將求和之后的 sum 值放到數(shù)組的第一個(gè)位置,然后再將新的數(shù)據(jù)插入好芭。但如果數(shù)組一開始就有空閑空間残揉,則直接將數(shù)據(jù)插入數(shù)組。

那這段代碼的時(shí)間復(fù)雜度是多少呢尊沸?你可以先用我們剛講到的三種時(shí)間復(fù)雜度的分析方法來分析一下。

最理想的情況下贤惯,數(shù)組中有空閑空間洼专,我們只需要將數(shù)據(jù)插入到數(shù)組下標(biāo)為 count 的位置就可以了,所以最好情況時(shí)間復(fù)雜度為 O(1) 孵构。最壞的情況下屁商,數(shù)組中沒有

空閑空間了,我們需要先做一次數(shù)組的遍歷求和颈墅,然后再將數(shù)據(jù)插入蜡镶,所以最壞情況時(shí)間復(fù)雜度為 O(n) 溯职。

那平均時(shí)間復(fù)雜度是多少呢?答案是 O(1) 帽哑。我們還是可以通過前面講的概率論的方法來分析谜酒。

假設(shè)數(shù)組的長(zhǎng)度是 n ,根據(jù)數(shù)據(jù)插入的位置的不同妻枕,我們可以分為 n 種情況僻族,每種情況的時(shí)間復(fù)雜度是 O(1) 。除此之外屡谐,還有一種 “ 額外 ” 的情況述么,就是在數(shù)組沒有空

閑空間時(shí)插入一個(gè)數(shù)據(jù),這個(gè)時(shí)候的時(shí)間復(fù)雜度是 O(n) 愕掏。而且度秘,這 n+1 種情況發(fā)生的概率一樣,都是 1/(n+1) 饵撑。所以剑梳,根據(jù)加權(quán)平均的計(jì)算方法,我們求得的平均時(shí)

間復(fù)雜度就是:


至此為止滑潘,前面的最好垢乙、最壞、平均時(shí)間復(fù)雜度的計(jì)算语卤,理解起來應(yīng)該都沒有問題追逮。但是這個(gè)例子里的平均復(fù)雜度分析其實(shí)并不需要這么復(fù)雜,不需要引入概率

論的知識(shí)粹舵。這是為什么呢钮孵?我們先來對(duì)比一下這個(gè) insert() 的例子和前面那個(gè) find() 的例子,你就會(huì)發(fā)現(xiàn)這兩者有很大差別眼滤。

首先巴席,find()函數(shù)在極端情況下,復(fù)雜度才為O(1)柠偶。但insert()在大部分情況下情妖,時(shí)間復(fù)雜度都為O(1)。只有個(gè)別情況下诱担,復(fù)雜度才比較高,為O(n)电爹。這是insert()第一

個(gè)區(qū)別于find()的地方蔫仙。

我們?cè)賮砜吹诙€(gè)不同的地方。對(duì)于insert()函數(shù)來說丐箩,O(1)時(shí)間復(fù)雜度的插入和O(n)時(shí)間復(fù)雜度的插入摇邦,出現(xiàn)的頻率是非常有規(guī)律的恤煞,而且有一定的前后時(shí)序關(guān)

系,一般都是一個(gè) O(n) 插入之后施籍,緊跟著 n-1 個(gè) O(1) 的插入操作居扒,循環(huán)往復(fù)。

所以丑慎,針對(duì)這樣一種特殊場(chǎng)景的復(fù)雜度分析喜喂,我們并不需要像之前講平均復(fù)雜度分析方法那樣,找出所有的輸入情況及相應(yīng)的發(fā)生概率竿裂,然后再計(jì)算加權(quán)平均

值玉吁。

針對(duì)這種特殊的場(chǎng)景,我們引入了一種更加簡(jiǎn)單的分析方法:攤還分析法腻异,通過攤還分析得到的時(shí)間復(fù)雜度我們起了一個(gè)名字进副,叫均攤時(shí)間復(fù)雜度。

那究竟如何使用攤還分析法來分析算法的均攤時(shí)間復(fù)雜度呢悔常?

我們還是繼續(xù)看在數(shù)組中插入數(shù)據(jù)的這個(gè)例子影斑。每一次 O(n) 的插入操作,都會(huì)跟著 n-1 次 O(1) 的插入操作机打,所以把耗時(shí)多的那次操作均攤到接下來的 n-1 次耗時(shí)少的

操作上鸥昏,均攤下來,這一組連續(xù)的操作的均攤時(shí)間復(fù)雜度就是 O(1) 姐帚。這就是均攤分析的大致思路吏垮。你都理解了嗎?

均攤時(shí)間復(fù)雜度和攤還分析應(yīng)用場(chǎng)景比較特殊罐旗,所以我們并不會(huì)經(jīng)常用到膳汪。為了方便你理解、記憶九秀,我這里簡(jiǎn)單總結(jié)一下它們的應(yīng)用場(chǎng)景遗嗽。如果你遇到了,知道

是怎么回事兒就行了鼓蜒。

對(duì)一個(gè)數(shù)據(jù)結(jié)構(gòu)進(jìn)行一組連續(xù)操作中痹换,大部分情況下時(shí)間復(fù)雜度都很低,只有個(gè)別情況下時(shí)間復(fù)雜度比較高都弹,而且這些操作之間存在前后連貫的時(shí)序關(guān)系娇豫,這個(gè)

時(shí)候,我們就可以將這一組操作放在一塊兒分析畅厢,看是否能將較高時(shí)間復(fù)雜度那次操作的耗時(shí)冯痢,平攤到其他那些時(shí)間復(fù)雜度比較低的操作上。而且,在能夠應(yīng)用

04|復(fù)雜度分析(下):淺析最好浦楣、最壞袖肥、平均、均攤時(shí)間復(fù)雜度

file:///F/temp/geektime/數(shù)據(jù)結(jié)構(gòu)與算法之美/04復(fù)雜度分析(下):淺析最好振劳、最壞椎组、平均、均攤時(shí)間復(fù)雜度.html[2019/1/15 15:35:12]

均攤時(shí)間復(fù)雜度分析的場(chǎng)合历恐,一般均攤時(shí)間復(fù)雜度就等于最好情況時(shí)間復(fù)雜度寸癌。

盡管很多數(shù)據(jù)結(jié)構(gòu)和算法書籍都花了很大力氣來區(qū)分平均時(shí)間復(fù)雜度和均攤時(shí)間復(fù)雜度,但其實(shí)我個(gè)人認(rèn)為夹供,均攤時(shí)間復(fù)雜度就是一種特殊的平均時(shí)間復(fù)雜度灵份,

我們沒必要花太多精力去區(qū)分它們。你最應(yīng)該掌握的是它的分析方法哮洽,攤還分析填渠。至于分析出來的結(jié)果是叫平均還是叫均攤,這只是個(gè)說法鸟辅,并不重要氛什。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市匪凉,隨后出現(xiàn)的幾起案子枪眉,更是在濱河造成了極大的恐慌,老刑警劉巖再层,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贸铜,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡聂受,警方通過查閱死者的電腦和手機(jī)蒿秦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛋济,“玉大人棍鳖,你說我怎么就攤上這事⊥肼茫” “怎么了渡处?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)祟辟。 經(jīng)常有香客問我医瘫,道長(zhǎng),這世上最難降的妖魔是什么川尖? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任登下,我火速辦了婚禮茫孔,結(jié)果婚禮上叮喳,老公的妹妹穿的比我還像新娘被芳。我一直安慰自己,他們只是感情好馍悟,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布畔濒。 她就那樣靜靜地躺著,像睡著了一般锣咒。 火紅的嫁衣襯著肌膚如雪侵状。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天毅整,我揣著相機(jī)與錄音趣兄,去河邊找鬼。 笑死悼嫉,一個(gè)胖子當(dāng)著我的面吹牛艇潭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播戏蔑,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼蹋凝,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了总棵?” 一聲冷哼從身側(cè)響起鳍寂,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎情龄,沒想到半個(gè)月后迄汛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡骤视,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年鞍爱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尚胞。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡硬霍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出笼裳,到底是詐尸還是另有隱情唯卖,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布躬柬,位于F島的核電站拜轨,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏允青。R本人自食惡果不足惜橄碾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧法牲,春花似錦史汗、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至悼瓮,卻和暖如春戈毒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背横堡。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工埋市, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人命贴。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓道宅,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親套么。 傳聞我的和親對(duì)象是個(gè)殘疾皇子培己,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348