常見的數量級函式:
在上圖中,我們可以看到當 n 很小時,函式之間不易區分,很難說誰處於主導地位,但是當 n 增大時,我們就能看到很明顯的區別,誰是老大一目了然:
o(1) < o(logn) < o(n) < o(nlogn) < o(n^2) < o(n^3) < o(2^n)
更加詳細的解釋:
先從 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(n^2) 是說,計算的複雜度隨著樣本個數的平方數增長。這個例子在演算法裡面,就是那一群比較挫的排序,比如冒泡、選擇等等。沿著我們剛才的說的那個試卷的例子,等我們找出最高的分數之後,放在一邊另起一堆,然後用同樣的方法找第二高的分數,再放到新堆上…… 這樣我們做n次,試卷就按照分數從低到高都排好了。因為有n份試卷,所以這種翻試卷,找最高分的行為,我們要做n次,每次的複雜度是 o(n) ,那麼n個 o(n) 自然就是 o(n^2).
在比如說構建乙個網路,每個點都和其他的點相連。顯然,每當我們增加乙個點,其實就需要構建這個點和所有現存的點的連線,而現存的點的個數是n,所以每增加1,就需要增加n個連線,那麼如果我們增加n個點呢,那這個連線的個數自然也就是 n^2 量級了。
無論是翻試卷,還是建立網路,每增加乙份試卷,每增加乙個點,都需要給演算法執行人帶來n量級的工作量,這種演算法的複雜度就是 o(n^2) 。
然後是 o(nlogn) ,這恐怕是常見演算法複雜度裡面相對最難理解的,就是這個log怎麼來的。前面那個n,代表執行了n次 log(n) 的操作,所以理解了log(n),就理解了nlog(n)。
o(logn) 的演算法複雜度,典型的比如二分查詢。設想一堆試卷,已經從高到底按照分數排列了,我們現在想找到有沒有59分的試卷。怎麼辦呢?先翻到中間,把試卷堆由中間分成上下兩堆,看中間這份是大於還是小於59,如果大於,就留下上面那堆,別的丟掉,如果小於,就留下下面那堆,丟掉上面。然後按照同樣的方法,每次丟一半的試卷,直到丟無可丟為止。
假如有32份試卷,你丟一次,還剩16份 ,丟兩次,還剩下8 份,丟三次,就只剩下4份了,可以這麼一直丟下去,丟到第五次,就只剩下乙份了。而 log_2(32) = 5 。也就是我們一次丟一半,總要丟到只有乙份的時候才能出結果,如果有n份,那麼顯然我們就有:
\frac = 1\rightarrow k = log_2 n
也就是大約需要 log_2 n 次,才能得出「找到」或者「沒找到」的結果。當然你說你三分查詢,每次丟三分之二可不可以?當然也可以,但是演算法複雜度在這裡是忽略常數的,所以不管以2為底,還是以什麼數為底,都統一的寫成 log(n) 的形式。
理解了這一點,就可以理解快速排序為什麼是 o(nlogn) 了。比如對一堆帶有序號的書進行排序,怎麼快呢?就是隨便先選一本,然後把號碼大於這本書的扔右邊,小於這本書的扔左邊。因為每本書都要比較一次,所以這麼搞一次的複雜度是 o(n) ,那麼快排需要我們搞多少次呢?這個又回到了二分查詢的邏輯了,每次都把書堆一分為二,請問分多少次手裡才能只剩下一本書呢?答案還是 logn 。而從**的角度來說,在到達大小為一的數列之前,我們也是需要作 logn 次巢狀的呼叫。
複雜度分析 時間複雜度分析和空間複雜度分析
其實,只要講到資料結構與演算法,就一定離不開時間 空間複雜度分析。而且我個人認為,複雜度分析是整個演算法學習的精髓,只要掌握了它,資料結構和演算法的內容基本上就掌握了一半。1.時間複雜度分析 對於剛才羅列的複雜度量級,我們可以粗略地分為兩類,多項式量級和非多項式量級。其中,非多項式量級只有兩個 o ...
複雜度分析 時間複雜度 空間複雜度
執行效率是演算法的乙個重要的考量指標,演算法的執行效率用時間 空間複雜度來衡量。今天我們來學習一下複雜度的分析。通常我們可以通過執行程式來獲得演算法的真正的執行時間,這種方法我們可以稱為事後統計法,但這種方法得到的是具體的資料,測試結果很依賴測試環境,而且受資料規模影像最大。因此,我們需要乙個不需要...
複雜度分析(上)時間複雜度 空間複雜度
為了肉眼 實時 快速地來分析出 的複雜度,我們需要乙個不用具體的測試資料來測試,就可以粗略地估計演算法的執行效率的方法。時間複雜度 空間複雜度 表示演算法的執行時間與資料規模之間的增長關係。每行 對應的 cpu 執行的個數 執行的時間都不一樣,但是,我們這裡只是粗略估計,所以可以假設每行 執行的時間...