1. 程式人生 > >如何進行演算法的複雜度分析?

如何進行演算法的複雜度分析?

![file](https://img2020.cnblogs.com/other/1648938/202007/1648938-20200721070952420-920074182.jpg) # 前言 > 本篇文章收錄於專輯:[http://dwz.win/HjK](http://dwz.win/HjK) 你好,我是彤哥,一個每天爬二十六層樓還不忘讀原始碼的硬核男人。 大家都知道,資料結構與演算法解決的主要問題就是“快”和“省”的問題,即如何讓程式碼執行得更快, 如何讓程式碼更節省儲存空間。 所以,“快”和“省”是衡量一個演算法非常重要的兩項指標,也就是我們經常聽到的時間複雜度和空間複雜度分析。 那麼,為什麼需要複雜度分析呢?複雜度分析的方法論是什麼呢? 這就是我們本節要解決的問題。 好了,進入今天的學習吧。 # 為什麼需要複雜度分析? 首先,我們來思考一個問題:對於兩個演算法,我們如何評判誰執行得更快,誰執行時更節省記憶體? 你可能會說,這還不簡單,把這兩個演算法執行一遍,統計下執行時間和佔用記憶體不就可以了嗎? 沒錯,這確實是一種不錯的方法,而且它還有個非常形象的名字:**事後統計法**。 但是,這種統計方法具有非常明顯的問題: 1. 不同的輸入對結果影響很大 對於一些輸入,可能演算法A執行得更快;對於另外一些輸入,可能演算法B執行得更快。比如,我們後面要學習的排序演算法,輸入的有序性對於不同的排序演算法的影響是完全不同的。 2. 不同的機器對結果影響很大 對於同樣的輸入,可能在一臺機器上演算法A更快,而在另外一臺機器上演算法B更快。比如,演算法A可以利用多核而演算法B不能,那麼CPU的核數對這兩個演算法的影響將截然不同。 3. 資料規模對結果影響很大 當資料規模小時,可能演算法A更快,而資料規模變大時,可能演算法B更快。比如,我們後面要學習的排序演算法,當資料規模比較小時,插入排序反而比歸併排序更快。 所以,我們需要一種可以不用實際執行演算法,就可以估計演算法執行效率的方法。 這也就是我們所說的複雜度分析。 那麼,怎麼進行復雜度分析呢?有沒有什麼方法論呢? 還真有,這個方法論叫作**漸近分析法**。 # 什麼是漸近分析法? 漸近分析法,是指將演算法執行的效率與輸入的規模進行掛鉤,隨著輸入規模的增大,演算法執行所需要的時間(或空間)將呈現一種什麼樣的趨勢,這種趨勢就叫作**漸近**,而這種方法就叫作**漸近分析法**。 概念可能比較拗口,我舉個簡單的例子,對於給定的一個有序陣列,我要查詢其中某個值所在的位置,比如,查詢8這個元素,有哪些方法呢? ![file](https://img2020.cnblogs.com/other/1648938/202007/1648938-20200721070952640-935718909.jpg) 簡單暴力點的方法,從頭遍歷,查詢到該元素即返回。 ![file](https://img2020.cnblogs.com/other/1648938/202007/1648938-20200721070952940-853937590.jpg) 更友好一點的方法,採用二分法,每次定位到資料的中間位置,看其值與目標值的大小,判斷是在左邊還是右邊繼續以二分的方式查詢。 ![file](https://img2020.cnblogs.com/other/1648938/202007/1648938-20200721070953145-1419684349.jpg) 上面我們舉的例子的輸入規模是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 = ? 我了個去,這個結果等於多少? 是時候展現真正的實力了: ![file](https://img2020.cnblogs.com/other/1648938/202007/1648938-20200721070953327-1606872203.jpg) 你可能要罵娘了,對於我一個小學畢業的,難道我沒辦法學習資料結構與演算法了? No,No,No,肯定不能這麼玩,那麼,應該怎麼玩呢?我們下一節接著講。 # 後記 本節,我們從演算法執行效率方面闡述了為什麼需要複雜度分析,並介紹了複雜度分析的方法,即漸近分析法,如果嚴格地遵循漸近分析法,需要大量的數學知識,這無疑增加了我們分析演算法的難度,那麼,有沒有什麼更省心地計算複雜度的方法呢? > 關注公眾號“彤哥讀原始碼”,解鎖更多原始碼、基礎、架構