1. 程式人生 > >如何理解演算法時間複雜度的表示

如何理解演算法時間複雜度的表示

先從O(1) 來說,理論上雜湊表就是O(1)。因為雜湊表是通過雜湊函式來對映的,所以拿到一個關鍵 字,用雜湊函式轉換一下,就可以直接從表中取出對應的值。和現存資料有多少毫無關係,故而每次執行 該操作只需要恆定的時間(當然,實際操作中存在衝突和衝突解決的機制,不能保證每次取值的時間是完 全一樣的)。舉個現實的例子,比如我的身後有一排櫃子,裡面有香蕉(代號B),蘋果(代號A),葡萄 (G),現在你說A,我迅速的就把蘋果遞過來了;你說B,我迅速就把香蕉遞過來了。就算你再增加菠蘿 (P)、火龍果(H),但是你說一個代號,我遞給你相應的水果這個速度是幾乎不會變的。


至於O(n) ,這個就是說隨著樣本數量的增加,複雜度也隨之線性增加。典型的比如數數。如果一個人 從1數到100,需要100秒,那麼從1到200,基本上不會小於200秒,所以數數就是一個O(n) 複雜度的 事情。一般來說,需要序貫處理的演算法的複雜度,都不會低於O(n) 。比如說,如果我們要設計一個算 法從一堆雜亂的考試的卷子裡面找出最高的分數,這就需要我們從頭到尾看完每一份試卷,顯然試卷越 多,需要的時間也越多,這就是一個O(n) 複雜度的演算法。

O(n2) 是說,計算的複雜度隨著樣本個數的平方數增長。這個例子在演算法裡面,就是那一群比較挫的 排序,比如冒泡、選擇等等。沿著我們剛才的說的那個試卷的例子,等我們找出最高的分數之後,放在一 邊另起一堆,然後用同樣的方法找第二高的分數,再放到新堆上…… 這樣我們做n次,試卷就按照分數從低 到高都排好了。因為有n份試卷,第一次翻卷找最高分,要找n份試卷,第二次翻卷要找n-1份試卷,第三次翻卷要找n-2份試卷.... ,總共要找n+(n-1)+(n-2)...+1次,也就是 (n+1)n/2次,   捨去常數,就是n2次. 演算法時間複雜度就是O(n2).    再比如說構建一個網路,每個點都和其他的點相連。顯然,每當我們增加一個點,其實就需要構建這個點 和所有現存的點的連線,而現存的點的個數是n,所以每增加1,就需要增加n個連線,那麼如果我們增加n 個點呢,那這個連線的個數自然也就是 O(n2) 量級了。

無論是翻試卷,還是建立網路,每增加一份試卷,每增加一個點,都需要給演算法執行人帶來n量級的工作 量,這種演算法的複雜度就是 O(n2)。

然後是O(nlogn) ,這是常見演算法複雜度裡面相對難理解的,就是這個log怎麼來的。前面那個 n,代表執行了n次 的操作,所以理解了log(n),就理解了nlog(n)。

O(logn)的演算法複雜度,典型的比如二分查詢。設想一堆試卷,已經從高到底按照分數排列了,我們現 在想找到有沒有59分的試卷。怎麼辦呢?先翻到中間,把試卷堆由中間分成上下兩堆,看中間這份是大於 還是小於59,如果大於,就留下上面那堆,別的丟掉,如果小於,就留下下面那堆,丟掉上面。然後按照 同樣的方法,每次丟一半的試卷,直到丟無可丟為止。

具體舉一個例子, 假如有32份試卷,你丟一次,還剩16份 ,丟兩次,還剩下8 份,丟三次,就只剩下4份了,可以這麼一直 丟下去,丟到第五次,就只剩下一份了。也就是我們一次丟一半,總要丟到只有一份的時候才能出那個要找的59分的卷子,一共執行了5次,2的5次方=32, 如果有n份,也就是大約需要log2n 次,才能得出“找到”或者“沒找到”的結果。當然你說你三分查詢,每次丟三 分之二可不可以?當然也可以,但是演算法複雜度在這裡是忽略常數的,所以不管以2為底,還是以什麼數為 底,都統一的寫成 的形式。

理解了這一點,就可以理解快速排序為什麼是 O(nlog(n))了。比如對一堆帶有序號的n本書進行排序,怎麼快速排序呢?就是隨便先選一本,然後把號碼大於這本書的扔右邊,小於這本書的扔左邊。因為每本書都要比較 一次,所以這麼搞一次的複雜度是O( n),那麼快速排序需要我們重複多少次呢?這又回到了二分查詢的邏 輯了,經過第一次後,這堆書一分為二堆,  每堆是n/2本 , 在這兩堆上再重複上面的步驟, 每堆排序一次的步驟n/2次  兩堆共n/2+n/2=n次 , 再兩堆分四堆,每堆的步驟是n/4次, 四堆共n/4+n/4+n/4+n/4=n次....  所以每次分堆後,總的步驟次數都是n次, 請問分多少次手裡每堆裡只有一本書呢?答案還是log2n 。所以分堆次數是log2n ,而每分一次堆後排序總步驟是n次,因此總的次數是nlogn.也就是時間