1. 程式人生 > >day 5複雜度分析(1)

day 5複雜度分析(1)

如何分析、統計演算法的執行效率和資源消耗?

其實,資料結構和演算法說到底,解決的是“快”和“省”的問題,即如何讓程式碼執行得更快,如何讓程式碼更省儲存空間。所以,執行效率是演算法的一個非常重要的考量指標,所以今天就主要總結一下能衡量演算法程式碼執行效率的時間、空間複雜度分析

1、為什麼需要複雜度分析: 在日常的工作學習中我會想,我把程式碼跑一遍,通過統計、監控,就能得到演算法執行的時間和佔用的記憶體大小。為什麼還要做時間空間複雜度分析呢?這種分析方法能比我實實在在跑一遍得到的資料更準確嗎?

不過靜下來認真思考一下,首先,我這種評估演算法執行效率的方法肯定是正確的,但是,這種統計方法有非常大的侷限性。

  • a、測試結果非常依賴測試環境。 測試環境中硬體配置的不同會對測試結果有很大的影響。比如,拿同樣一段程式碼,分別用Intel Core i9處理器和Intel Core i3處理器來執行,不用多說,i9處理器要比i3處理器執行的速度快很多。還有,比如原本在這臺機器上a程式碼執行的速度比b程式碼快,等我們換到另外一臺機器上時,可能會得到截然相反的結果。
  • b、測試結果受資料規模的影響很大。 拿一個排序演算法來舉個例子。對同一個排序演算法,待排序資料的有序度不一樣,排序的執行時間就會有很大差別。極端情況下,如果資料已經是有序的了,那排序演算法不需要做任何操作,執行時間就會非常短。除此之外,如果測試資料規模太小,測試結果可能無法真實地反映演算法的效能。比如對於小規模的資料排序,插入排序可能反倒會比快速排序要快。

所以綜上所述,我需要一個不用具體的測試資料來測試,就可以粗略地估計演算法的執行效率方法-----時間、空間複雜度分析法。

2、大 O 複雜度表示法 演算法的執行效率,粗略地講就是演算法程式碼執行的時間。但是,如何在不執行程式碼的情況下,用“心算”的方式得到一段程式碼的執行時間呢? 從CPU的角度來看,演算法程式碼的每一行都執行著類似的操作:讀資料–運算–寫資料。可以假設每行程式碼執行的時間都一樣,為unit_time。所以,所有演算法程式碼執行的總時間 T(n) 與每行程式碼的執行次數n成正比。 所以,將這個規律總結成一個公式,即大 O 表示法:

T(n) = O f(n)
解釋一下這個公式:其中,T(n) 表示程式碼執行的時間;n 表示資料規模的大小;f(n) 表示每行程式碼執行的次數總和;O 表示程式碼的執行時間 T(n) 和 f(n) 表示式成正比。

這就是大 O 時間複雜度表示法。大 O 時間複雜度實際上並不具體表示程式碼真正的執行時間,而是表示程式碼執行時間隨資料規模增長的變化趨勢,所以,也叫作漸進時間複雜度(asymptotic time complexity),簡稱時間複雜度。

3、時間複雜度分析

  • a 、就像上文提到的,大 O 這種複雜度表示方法只是表示一種變化趨勢,所以通常會忽略掉公式中的常量、低階、係數,只需要記錄一個最大階的量級就可以了。所以,我們在分析一個演算法,一段程式碼的時間複雜度的時候,也只關注迴圈執行次數最多的那一段程式碼就可以了
  • b、加法法則:**總的時間複雜度就等於量級最大的那段程式碼的時間複雜度。**如果將這個規律抽象成公式就是:
如果: T1(n) = O(f(n)) , T2(n) = O(g(n));
那麼 T(n) = T1(n) + T2(n) = max(O(f(n), O(g(n))) = O(max(f(n), g(n))).
  • c、乘法法則:巢狀程式碼的複雜度等於巢狀內外程式碼複雜度的乘積
如果: T1(n) = O(f(n)) , T2(n) = O(g(n));
那麼 T(n) = T1(n) * T2(n) = O(f(n)) * O(g(n)) = O(f(n) * g(n)).

4、空間複雜度分析 前面講到,時間複雜度的全稱是漸進時間複雜度,表示演算法的執行時間與資料規模之間的增長關係,類比一下,空間複雜度的全稱就是漸進空間複雜度(asymptotic space complexity),表示演算法的儲存空間與資料規模之間的增長關係。

5、常用的複雜度級別 **多項式階:**隨著資料規模的增長,演算法的執行時間和空間佔用,按照多項式的比例增長。包括: O(1)(常數階)、O(logn)(對數階)、O(n)(線性階)、O(nlogn)(線性對數階)、O(n^2)(平方階)、O(n^3)(立方階) **非多項式階:**隨著資料規模的增長,演算法的執行時間和空間佔用暴增,這類演算法效能極差。包括: O(2^n)(指數階)、O(n!)(階乘階)

6、如何掌握好複雜度分析方法 複雜度分析並不難,關鍵在於多讀多練。