對於時間複雜度的分析,一般使用大O複雜度表示法,表示代碼執行時間隨數據規模增加的變化趨勢,因此,也叫做漸進時間複雜度(asymptotic time complexity),簡稱時間複雜度。web
用公式表示,就是 T(n) = O(f(n))
表示,其中 T(n)
表示算法執行總時間,f(n)
表示每行代碼執行總次數,而 n
表示數據的規模。算法
因爲時間複雜度描述的是算法執行時間與數據規模的增加變化趨勢,因此常量階、低階以及係數實際上對這種增加趨勢不產決定性影響,因此在作時間複雜度分析時能夠忽略這些項。數組
具體分析的時候,有下列三個方法:數據結構
按照數量級遞增,常見的時間複雜度量級有:數據結構和算法
O(1)
O(logn)
O(n)
O(nlogn)
O(n^2)
,立方階
O(n^3)
...k次階
O(n^k)
O(2^n)
O(n!)
其中,最後兩種狀況是很是糟糕的狀況,固然 O(n^2)
也是一個能夠繼續進行優化的狀況。編輯器
接下來簡單介紹上述複雜度中的幾種比較常見的:函數
O(1)
表示的是常量級時間複雜度,也就是只要代碼的執行時間不隨 n 的增大而增加,都記做 O(1)
。通常只要算法不包含循環語句和遞歸語句,時間複雜度都是 O(1)
性能
像下列代碼,有 3 行,但時間複雜度依然是O(1)
,而非 O(3)
。測試
a = 3
b = 4
print(a + b)
O(logn)
也是一個常見的時間複雜度,下面是一個 O(logn)
的代碼例子:優化
i = 1
count = 0
n = 20
while i <= n:
count += 1
i *= 2
print('while 循環運行了 {} 次'.format(count))
這段代碼其實就是每次循環都讓變量 i 乘以 2,直到其大於等於 n,這裏我設置 n=20,而後運行了後,輸出結果是循環運行了 5 次。
實際上這段代碼的結束條件,就是求 2^x=n
中的 x
是等於多少,那麼循環次數也就知道了,而求 x
的數值,方法就是 ,那麼時間複雜度就是
假如上述代碼進行簡單的修改,將 i *= 2
修改成 i *= 3
,那麼同理能夠獲得時間複雜度就是 。
但在這裏,不管是以哪一個爲對數的底,咱們都把對數階的時間複雜度記爲 O(logn)
。
這裏主要緣由有兩個:
基於這兩個緣由,對數階的時間複雜度都忽略了底,統一爲 O(logn)
。
至於 O(nlogn)
,根據乘法法則,只須要將對數階複雜度的代碼,運行 n 次,就能夠獲得這個線性對數階複雜度了。
注意, O(nlogn)
是很是常見的時間複雜度,經常使用的排序算法如歸併排序、快速排序的時間複雜度都是 O(nlogn)
前面介紹的狀況都是隻有一個數據規模 n
,但這裏介紹有兩個數據規模的狀況--m
和 n
。
# O(m+n)
def cal(n, m):
result = 0
for i in range(n):
result += i
for j in range(m):
result += j * 2
return result
簡單的代碼示例如上述所示,若是事先沒法評估 m
和 n
的量級大小,那麼這裏的時間複雜度就無法選擇量級最大的,因此其時間複雜度就是 O(m+n)
。
同理,對於嵌套循環,就是 O(m*n)
的時間複雜度了。
這四種複雜度的定義以下:
爲何會有這四種複雜度呢?緣由是:
同一段代碼在不一樣狀況下時間複雜度會出現量級差別,爲了更全面、更準確描述代碼的時間複雜度,引入這四種複雜度的概念;
但一般除非代碼是出現量級差異的時間複雜度,才須要區分這四種複雜度,大多數狀況都不須要區分它們。
下面是給出第一個代碼例子:
# 在數組 arr 中查找目標數值 x
def find(arr, x):
for val in arr:
if val == x:
return True
return False
這個例子假設數組 arr
的長度是 n
,那麼它最好的狀況,就是第一個數值就是須要查找的 x
,此時複雜度是 O(1)
,但最壞狀況就是最後一個數值或者不存在須要查找的 x
,那麼此時就遍歷一遍數組,複雜度就是 O(n)
,所以這段代碼最好和最壞狀況是會出現量級差異的,O(1)
和 O(n)
分別是最好狀況複雜度和最壞狀況複雜度。
而這段代碼的平均狀況時間複雜度是 O(n)
,具體分析就是首先考慮全部可能的狀況以及對應出現的機率,可能發生的狀況先分爲兩種,存在和不存在須要查找的數值 x
,也就是分別是 1/2 的機率,而後對於存在的狀況下,又有 n
種狀況,即出如今數組任意位置的機率都是均等的,那麼它們的機率乘以存在的機率就是 1/2n
,接着再考慮每種狀況須要搜索的元素個數,其實就是代碼執行的次數,這個分別就是從 1 到 n,而且對於不存在的狀況,也是 n ,須要遍歷一遍數組才發現不存在,因此平均時間複雜度的計算過程以下:
計算獲得的就是機率論中的加權平均值,也叫指望值,因此平均時間複雜度的全稱應該叫加權平均時間複雜度或者指望時間複雜度。
這裏用大 O 表示法表示,而且去掉常量和係數後,就是 O(n)。
最後介紹下均攤時間複雜度,須要知足如下兩個條件才使用:
1)代碼在絕大多數狀況下是低級別複雜度,只有極少數狀況是高級別複雜度;
2)低級別和高級別複雜度出現具備時序規律。均攤結果通常都等於低級別複雜度。
和時間複雜度的定義相似,空間複雜度全稱就是漸進空間複雜度(asymptotic space complexity),表示算法的存儲空間與數據規模之間的增加關係。
簡單介紹下一個程序所須要的空間主要由如下幾個部分構成:
參考: