前言
本篇文章收錄於專輯:http://dwz.win/HjK算法
你好,我是彤哥,一個天天爬二十六層樓還不忘讀源碼的硬核男人。數組
你們都知道,數據結構與算法解決的主要問題就是「快」和「省」的問題,即如何讓代碼運行得更快, 如何讓代碼更節省存儲空間。數據結構
因此,「快」和「省」是衡量一個算法很是重要的兩項指標,也就是咱們常常聽到的時間複雜度和空間複雜度分析。架構
那麼,爲何須要複雜度分析呢?複雜度分析的方法論是什麼呢?學習
這就是咱們本節要解決的問題。3d
好了,進入今天的學習吧。blog
爲何須要複雜度分析?
首先,咱們來思考一個問題:對於兩個算法,咱們如何評判誰運行得更快,誰運行時更節省內存?排序
你可能會說,這還不簡單,把這兩個算法運行一遍,統計下運行時間和佔用內存不就能夠了嗎?內存
沒錯,這確實是一種不錯的方法,並且它還有個很是形象的名字:過後統計法。get
可是,這種統計方法具備很是明顯的問題:
-
不一樣的輸入對結果影響很大
對於一些輸入,可能算法A執行得更快;對於另一些輸入,可能算法B執行得更快。好比,咱們後面要學習的排序算法,輸入的有序性對於不一樣的排序算法的影響是徹底不一樣的。
-
不一樣的機器對結果影響很大
對於一樣的輸入,可能在一臺機器上算法A更快,而在另一臺機器上算法B更快。好比,算法A能夠利用多核而算法B不能,那麼CPU的核數對這兩個算法的影響將大相徑庭。
-
數據規模對結果影響很大
當數據規模小時,可能算法A更快,而數據規模變大時,可能算法B更快。好比,咱們後面要學習的排序算法,當數據規模比較小時,插入排序反而比歸併排序更快。
因此,咱們須要一種能夠不用實際運行算法,就能夠估計算法執行效率的方法。
這也就是咱們所說的複雜度分析。
那麼,怎麼進行復雜度分析呢?有沒有什麼方法論呢?
還真有,這個方法論叫做漸近分析法。
什麼是漸近分析法?
漸近分析法,是指將算法執行的效率與輸入的規模進行掛鉤,隨着輸入規模的增大,算法執行所須要的時間(或空間)將呈現一種什麼樣的趨勢,這種趨勢就叫做漸近,而這種方法就叫做漸近分析法。
概念可能比較拗口,我舉個簡單的例子,對於給定的一個有序數組,我要查找其中某個值所在的位置,好比,查找8這個元素,有哪些方法呢?
簡單暴力點的方法,從頭遍歷,查找到該元素即返回。
更友好一點的方法,採用二分法,每次定位到數據的中間位置,看其值與目標值的大小,判斷是在左邊仍是右邊繼續以二分的方式查找。
上面咱們舉的例子的輸入規模是8個元素的有序數組,目標值爲8,使用第二種方法明顯比第一種方法要快不少。
可是,若是查找的目標是1呢?
對於第一種方法,查找一次足矣。
對於第二種方法,須要查找3次。
此時,第二種方法又次於第一種方法了。
因此,比較兩個算法的執行效率,不能只考慮到個別元素,而應該顧及到全部元素的感覺。
咱們以數學的方法來統計兩種方法的平均執行效率,假設輸入規模擴展到n。
對於第一種方法,1號元素查找一次,2號元素查找兩次,3號元素查找三次……,而查找每一個元素的機率都是1/n。
因此,它的執行效率爲:1x1/n + 2x1/n + 3x1/n + ... nx1/n = nx(n+1)/2/n = (n+1)/2。
對於第二種方法,中間的元素有一個,查找一次,次中間的元素有兩個,查找兩次,次次中間的元素有四個,查找三次...,每次查找的規模都縮小一半,而查找每一個元素的機率都是1/n。
因此,它的執行效率爲:1x1x1/n + 2x2x1/n + 4x3x1/n + ... + 2^(log2(n)-2) x (log2(n)-1) x 1/n+ 2^(log2(n)-1) x log2(n) x 1/n = ?
我了個去,這個結果等於多少?
是時候展示真正的實力了:
你可能要罵娘了,對於我一個小學畢業的,難道我沒辦法學習數據結構與算法了?
No,No,No,確定不能這麼玩,那麼,應該怎麼玩呢?咱們下一節接着講。
後記
本節,咱們從算法執行效率方面闡述了爲何須要複雜度分析,並介紹了複雜度分析的方法,即漸近分析法,若是嚴格地遵循漸近分析法,須要大量的數學知識,這無疑增長了咱們分析算法的難度,那麼,有沒有什麼更省心地計算複雜度的方法呢?
關注公衆號「彤哥讀源碼」,解鎖更多源碼、基礎、架構知識!