首先,這和研究數據結構和算法的目的有關——「快」而「省」的解決問題。那麼如何衡量算法的性能呢?就須要算法複雜度分析。算法
其次,除了算法複雜度分析,還有一種方法能夠衡量複雜度,那就是「過後統計法」,即直接運行程序,統計須要的時間和空間。可是,這種方法有兩個問題:數組
1)結果很是依賴於測試環境。好比,用 Core i3 和用 Core i8 運行程序所需的時間是不一樣的;微信
2)結果受測試規模的影響特別大。好比,對有序數組進行排序的時間比對逆序數組排序的時間短;對於小規模數據而言,插入排序所需時間比快速排序要短。數據結構
因此,就須要有一種不用具體測試數據,也能估計算法執行效率的方法,就是算法複雜度分析,包括時間、空間複雜度分析。數據結構和算法
大 O 複雜度表示法能夠概括成下面一句話:函數
全部代碼的執行時間
T(n)
與每行代碼的執行次數 n 成正比。
即 T(n) = O(f(n))
。其中,f(n)
表示代碼的執行次數之和。大 O 符號(Big O notation)是用於描述函數漸進行爲的數學符號,它表明「order of...」(...階)。性能
例如,對於代碼:測試
function foo (n) { var i = 0; var j = 0; for (; i < n; i++) { j += i; } }
假設每行代碼的執行時間同樣,爲 unit_time。則第 二、3 行執行時間均爲 1 unit_time,第 四、5 行代碼執行時間均爲 n unit_time,整個函數的執行時間 T(n) = (2n + 2) * unit_time
。用大 O 複雜度表示法表示即爲 T(n) = O(2n + 2)
。spa
注意,大 O 時間複雜度並不具體表示代碼真正的執行時間,而是表示代碼執行時間隨數據規模增加的變化趨勢。因此,它也叫漸進時間複雜度,簡稱時間複雜度。code
當 n 很大時,不左右增加趨勢的低階、常量、係數都可忽略。因此,上面例子中的時間複雜度爲 O(n)
。
時間複雜度分析有下面幾個原則:
1)只關注循環執行次數最多的一段代碼;
2)加法原則:總複雜度等於量級最大的那段代碼的複雜度。用公式表示即爲:T1(n) = O(f(m)),T2(n) = O(g(n)),T1(n) + T2(m) = O(max(f(n), g(m)))
;
3)乘法原則:嵌套代碼的複雜度等於嵌套內外代碼複雜度的伺機。用公式表示即爲:T1(n) = O(f(m)),T2(n) = O(g(n)),T1(n) * T2(m) = O(f(n) * g(m))
常見的時間複雜度有如下幾種:
1)常量階:O(1)
2)對數階:O(logn)
3)線性階:O(n)
4)線性對數階:O(nlogn)
5)平方階:O(n ^ 2)
6)指數階:O(2 ^ n)
7)階乘階:O(n!)
其中,1)-5)爲多項式量級;6)、7)爲非多項式量級,所對應的算法問題被稱爲非肯定多項式問題(NP 問題,Non-Deterministic Polynomial)。
空間複雜度全稱爲漸進空間複雜度(asymptostic space complexity)。空間複雜度較爲簡單,常見的空間複雜度爲 O(1)
,O(n)
和 O(n ^ 2)
。
最後,用幾種複雜度的座標圖做爲結尾:
首發於微信公衆號《代碼寫完了》