算法是獨立存在的一種解決問題的方法和思想:python
對於算法而言,實現的語言並不重要,重要的是思想算法
通常狀況下,算法中基本操做重複執行的次數是問題規模n的某個函數,用T(n)
表示(語句頻度),如有某個輔助函數f(n)
,使得當n
趨近於無窮大時,T(n)/f(n)
的極限值爲不等於零的常數,則稱f(n)
是T(n)
的同數量級函數。記做T(n)=O(f(n))
,稱O(f(n))
爲算法的漸進時間複雜度(O是數量級的符號 ),簡稱時間複雜度。數組
求解算法時間複雜度的步驟:函數
找出算法中的基本語句,計算基本操做執行次數T(n)
oop
# 基本操做即算法中的每條語句(以;號做爲分割),語句的執行次數也叫作語句的頻度。在作算法分析時,通常默認爲考慮最壞的狀況。
計算基本語句的執行次數T(n)
的數量級spa
# 忽略常量、低次冪和最高次冪的係數,令f(n)=T(n)的數量級
用大O
來表示時間複雜度指針
# 當n趨近於無窮大時,若是lim(T(n)/f(n))的值爲不等於0的常數,則稱f(n)是T(n)的同數量級函數。記做T(n)=O(f(n)),即爲時間複雜度。
example_1
:code
n = 1000 # T(n) = 1 j = 1 # T(n) = 1 num1 = 1 # T(n) = 1 num2 = 2 # T(n) = 1 for i in range(0, n): # T(n) = n num1 += 1 # T(n) = n while j < n: # T(n) = n*log(n), 以2爲底 j *= 2 # T(n) = n*log(n), 以2爲底 num2 += 1 # T(n) = n*log(n), 以2爲底 print(num1, num2) # T(n) = 1
總的T(n):
\[ T(n) = 5 + 2n + 3nlog_2n \]blog
忽略掉T(n)
中的常量、低次冪和最高次冪的係數,數量級
\[ f(n) = nlog_2n \]排序
求極限
\[ lim(T(n)/f(n)) = lim((3nlog_2n + 2n + 4)/(nlog_2n) = 3 \]
因此時間複雜度能夠用大O表示,爲
\[ O(f(n)) = O(nlog_2n) \]
簡化的計算步驟:
能夠看出,決定算法複雜度的是執行次數最多的語句,這裏是num2 += 1
,j *= 2
通常也是最內循環的語句。而且,一般將求解極限是否爲常量也省略掉?
example_1
# 1.執行次數最多的語句爲 while j < n: j *= 2 num2 += 1 T(n) = 3n*log(n) # 2.數量級 f(n) = n*log(n) # 3.求極限及大O表示 T(n) = O(nlog(n))
分析算法,存在的幾種可能:
基本操做,即只有常數項,認爲是O(1)
順序結構,時間複雜度按加法進行計算
\[ T(n, m) = T1(n) + T2(m) = O(max(f(n), g(m))) \]
循環結構,時間複雜度按乘法進行計算
\[ T(n, m) = T1(n) * T2(m) = O(f(n)*g(m)) \]
分支結構,時間複雜度取最大值
常見的時間複雜度算法:
執行次函數舉例--總的T(n) | 時間複雜度 | 非正式術語 |
---|---|---|
12 | O(1) | 常數階 |
2n + 3 | O(n) | 線性階 |
3n^2 + 2n + 1 | O(n^2) | 平方階 |
5log(n) + 20 | O(log(n)) | 對數階 |
2n + 3nlog(n) + 19 | O(nlog(n)) | nlog(n)階 |
6n^3 + 2n^2 + 3n + 4 | O(n^3) | 立方階 |
2^n | O(2^n) | 指數階 |
n! + nlog(n) + 15 | O(n!) | 階乘 |
所消耗的時間從小到大:
\[ O(1) < O(log(n)) < O(n) < O(nlog_2(n)) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n) \]
example_2
n = 1000 x = 1 for i in range(0, n): x += 1 # T(n) = n for i in range(0, n): for j in range(0, n): x += 1 # T(n) = n*n print(x)
分析:
注意:T(n)
爲執行次數最多語句的頻度
for loop
, T(n) = n; f(n) = n
時間複雜度爲O(n)
for loop
, T(n) = n^2; f(n) = n^2
,時間複雜度爲O(n^2)
O(n + n^2) = O(n^2)
example_3
def func(n): for i in range(n): for j in range(i, n): print("Hello World j = %s" % j) # T(n) = (n^2)/2 + n/2
分析:
注意:==T(n)
爲執行次數最多語句的頻度
直接找到語句頻度最高的語句爲print("Hello World j = %s" % j)
,
# 當i爲0時,該語句執行n次 # 當i爲1時,該語句執行n-1次 # 。。。 # 因此該語句的T(n) = n + (n-1) + (n-2) + ... + 1 = (n+1)*n/2 = 0.5n^2 + 0.5n
數量級f(n) = n^2
極限存在,時間複雜度 = O(n^2)
example_4
def func(n): if n <= 1: return 1 else: return func(n - 1) + func(n - 2)
分析:
顯然運行次數,T(0) = T(1) = 1,同時 T(n) = T(n - 1) + T(n - 2) + 1,這裏的 1 是其中的加法算一次執行。 顯然 T(n) = T(n - 1) + T(n - 2) 是一個斐波那契數列,經過概括證實法能夠證實,當 n >= 1 時 T(n) < (5/3)^n,同時當 n > 4 時 T(n) >= (3/2)^n。 因此該方法的時間複雜度能夠表示爲 O((5/3)^n),簡化後爲 O(2^n)。
相似於時間複雜度的討論,一個算法的空間複雜度(Space Complexity),S(n)
定義爲該算法所耗費的存儲空間,它也是問題規模n的函數。漸近空間複雜度也經常簡稱爲空間複雜度。
空間複雜度(Space Complexity)是對一個算法在運行過程當中臨時佔用存儲空間大小的量度。一個算法在計算機存儲器上所佔用的存儲空間,包括:
常見算法空間複雜度: