第3課:算法復(fù)雜度分析(下):最好、最壞纺涤、平均译暂、均攤時間復(fù)雜度

最好、最壞時間復(fù)雜度

我們先看一個例子:

/*
 例1:查找x在數(shù)組中出現(xiàn)的位置撩炊,如果沒有找到外永,返回-1。n表示數(shù)組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;
}

當(dāng)把break語句注釋掉的時候衰抑,總是需要遍歷整個數(shù)組象迎,所以時間復(fù)雜度就是數(shù)組的長度,為O(n)呛踊。
當(dāng)有break語句的時候砾淌,如果找到x,則會提前退出(顯然這種寫法更高效)谭网。
我們知道x可能出現(xiàn)在數(shù)組的任何位置汪厨,可能是第一個(時間復(fù)雜度為O(1)),可能是最后一個(時間復(fù)雜度為O(n))愉择,也可能不存在數(shù)組中(時間復(fù)雜度為O(n))劫乱。

為了表示代碼在不同情況下的不同時間復(fù)雜度织中,我們需要引入三個概念:
最好情況時間復(fù)雜度、最壞情況時間復(fù)雜度和平均情況時間復(fù)雜度衷戈。

最好情況時間復(fù)雜度 就是狭吼,在最理想的情況下,執(zhí)行這段代碼的時間復(fù)雜度殖妇。
最壞情況時間復(fù)雜度 就是刁笙,在最糟糕的情況下,執(zhí)行這段代碼的時間復(fù)雜度
最好谦趣、最壞都是在對應(yīng)的都是極端情況下的代碼復(fù)雜度疲吸,發(fā)生的概率其實(shí)并不大。

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

平均時間復(fù)雜是為了更好地表示平均情況下的復(fù)雜度前鹅。
還是上面例1摘悴,結(jié)合概率知識,我們知道舰绘,要查找的變量x在數(shù)組中的位置蹂喻,有 n+1 種情況:在數(shù)組的0~n-1位置中和不在數(shù)組中。
我們暫且認(rèn)為每種情況發(fā)生的概率都一樣為:1/(n+1)除盏。
每種情況的時間復(fù)雜度為:1/(n+1)1叉橱、1/(n+1)2、1/(n+1)3...1/(n+1)n者蠕、1/(n+1)*n
所以平均時間復(fù)雜度為:(所有情況下的時間復(fù)雜度的總和)/(總情況數(shù)),即:

平均時間復(fù)雜度.png

大O表示法中掐松,可以省略掉系數(shù)踱侣、低階、常量大磺,所以抡句,得到的平均時間復(fù)雜度就是 O(n)。

其實(shí)上面的概率并不都是:1/(n+1)杠愧。
要查找的變量 x待榔,要么在數(shù)組里,要么就不在數(shù)組里流济。
我們假設(shè)在數(shù)組中與不在數(shù)組中的概率都為 1/2锐锣。
查找的數(shù)據(jù)出現(xiàn)在 0~n-1,這 n 個位置的概率也是一樣的绳瘟,為 1/n雕憔,則每種情況出現(xiàn)的概率為1/(2n)履婉。
每種情況的時間復(fù)雜度為:1/(2n)1覆享、1/(2n)2俄删、1/(2n)3...1/(2n)n
查找的數(shù)據(jù)不再數(shù)組里,則概率為1/2稍计。時間復(fù)雜度為:1/2*n。
所以平均時間復(fù)雜度為:(所有情況下的時間復(fù)雜度的總和)/(總情況數(shù))匕垫,即:

平均時間復(fù)雜度.png

去掉系數(shù)和常量娇钱,這段代碼的加權(quán)平均時間復(fù)雜度仍為 O(n)。
這個值就是概率論中的 加權(quán)平均值并扇,也叫作 期望值去团,所以平均時間復(fù)雜度的全稱應(yīng)該叫 加權(quán)平均時間復(fù)雜度或者 期望時間復(fù)雜度

均攤時間復(fù)雜度

均攤時間復(fù)雜度拜马,聽起來跟平均時間復(fù)雜度有點(diǎn)兒像渗勘。
對于初學(xué)者來說,這兩個概念確實(shí)非常容易弄混俩莽。

/*
 例2:n表示數(shù)組長度旺坠,count表示數(shù)組存儲數(shù)據(jù)的個數(shù)
 往數(shù)組中添加數(shù)據(jù),如果數(shù)組滿了扮超,則依次打印出來取刃,然后清空數(shù)組
*/
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++;
        }
}

分析下前面說的三種時間復(fù)雜度。
最好:最理想的情況下數(shù)組空閑出刷,時間復(fù)雜度為O(1)
最差:數(shù)組恰好不空閑璧疗,時間復(fù)雜度是 O(n)
平均:假設(shè)數(shù)組的長度是 n,根據(jù)數(shù)據(jù)插入的位置的不同馁龟,我們可以分為 n 種情況崩侠,
每種情況的時間復(fù)雜度是 O(1)。除此之外坷檩,還有一種“額外”的情況却音,就是在數(shù)組沒有空間時插入一個數(shù)據(jù),這個時候的時間復(fù)雜度是 O(n)矢炼。而且系瓢,這 n+1 種情況發(fā)生的概率一樣,都是 1/(n+1)句灌。所以夷陋,根據(jù)加權(quán)平均的計(jì)算方法,我們求得的平均時間復(fù)雜度就是:

平均時間復(fù)雜度.png

其實(shí)平均復(fù)雜度分析其實(shí)并不需要這么復(fù)雜胰锌,不需要引入概率論的知識骗绕。
相對例1的findIndex()函數(shù):findIndex()函數(shù)在極端情況下,復(fù)雜度才為 O(1)匕荸。
但 insert() 在大部分情況下爹谭,時間復(fù)雜度都為 O(1)。只有個別情況下復(fù)雜度才為 O(n)
不知道你有沒有注意到榛搔,對于 insert() 函數(shù)來說诺凡,O(1) 時間復(fù)雜度的插入和 O(n) 時間復(fù)雜度的插入东揣,
出現(xiàn)的頻率是非常有規(guī)律的,而且有一定的前后時序關(guān)系腹泌,一般都是一個 O(n) 插入之后嘶卧,緊跟著n個 O(1) 的插入操作,循環(huán)往復(fù)凉袱。
針對這樣一種特殊場景的復(fù)雜度分析芥吟,我們并不需要像之前講平均復(fù)雜度分析方法那樣,找出所有的輸入情況及相應(yīng)的發(fā)生概率专甩,然后再計(jì)算加權(quán)平均值钟鸵。
而是用一種更加簡單的分析方法:攤還分析法,通過攤還分析得到的時間復(fù)雜度我們起了一個名字涤躲,叫均攤時間復(fù)雜度棺耍。

那究竟如何使用攤還分析法來分析算法的均攤時間復(fù)雜度呢?
每一次 O(n) 的插入操作种樱,都會跟著 n次 O(1) 的插入操作蒙袍,
所以把耗時多的那次操作均攤到接下來的 n 次耗時少的操作上,均攤下來嫩挤,
這一組連續(xù)的操作的均攤時間復(fù)雜度就是 O(1)害幅。這就是均攤分析的大致思路。

對一個數(shù)據(jù)結(jié)構(gòu)進(jìn)行一組連續(xù)操作中岂昭,大部分情況下時間復(fù)雜度都很低以现,只有個別情況下時間復(fù)雜度比較高,
而且這些操作之間存在前后連貫的時序關(guān)系约啊,這個時候叼风,我們就可以將這一組操作放在一塊兒分析,
看是否能將較高時間復(fù)雜度那次操作的耗時棍苹,平攤到其他那些時間復(fù)雜度比較低的操作上。
而且茵汰,在能夠應(yīng)用均攤時間復(fù)雜度分析的場合枢里,一般均攤時間復(fù)雜度就等于最好情況時間復(fù)雜度。

小結(jié)

  • 同一段代碼蹂午,在不同輸入的情況下栏豺,復(fù)雜度量級有可能是不一樣的。所以有了最好豆胸、最壞奥洼、平均、均攤時間復(fù)雜度晚胡。
  • 其中最好灵奖、最壞情況下的時間復(fù)雜度分析起來比較簡單嚼沿。平均、均攤兩個復(fù)雜度分析相對比較復(fù)雜瓷患。
  • 在大多數(shù)情況下骡尽,我們并不需要區(qū)分最好、最壞擅编、平均情況時間復(fù)雜度三種情況攀细。很多時候,我們使用一個復(fù)雜度就可以滿足需求了爱态。只有同一塊代碼在不同的情況下谭贪,時間復(fù)雜度有量級的差距,我們才會使用這三種復(fù)雜度表示法來區(qū)分锦担。
  • 平均復(fù)雜度只在某些特殊情況下才會用到俭识,而均攤時間復(fù)雜度應(yīng)用的場景比它更加特殊、更加有限吆豹。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鱼的,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子痘煤,更是在濱河造成了極大的恐慌凑阶,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衷快,死亡現(xiàn)場離奇詭異宙橱,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蘸拔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門师郑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人调窍,你說我怎么就攤上這事宝冕。” “怎么了邓萨?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵地梨,是天一觀的道長。 經(jīng)常有香客問我缔恳,道長宝剖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任歉甚,我火速辦了婚禮万细,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘纸泄。我一直安慰自己赖钞,他們只是感情好腰素,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著仁烹,像睡著了一般耸弄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卓缰,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天计呈,我揣著相機(jī)與錄音,去河邊找鬼征唬。 笑死捌显,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的总寒。 我是一名探鬼主播扶歪,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼摄闸!你這毒婦竟也來了善镰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤年枕,失蹤者是張志新(化名)和其女友劉穎炫欺,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體熏兄,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡品洛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了摩桶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桥状。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖硝清,靈堂內(nèi)的尸體忽然破棺而出辅斟,到底是詐尸還是另有隱情,我是刑警寧澤芦拿,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布砾肺,位于F島的核電站,受9級特大地震影響防嗡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜侠坎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一蚁趁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧实胸,春花似錦他嫡、人聲如沸番官。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽徘熔。三九已至,卻和暖如春淆党,著一層夾襖步出監(jiān)牢的瞬間酷师,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工染乌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留山孔,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓荷憋,卻偏偏與公主長得像台颠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子勒庄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355