(一)漸進符號(這裏暫時只考慮大O)算法
以輸入規模n爲自變量創建的時間複雜度實際上仍是較複雜的,例如an2+bn+c,不只與輸入規模有關,還與係數a、b和c有關。此時對該函數進一步抽象,僅考慮運行時間的增加率或稱爲增加的量級,如忽略上式中的低階項、高階項的係數,僅考慮n2。當輸入規模大到只與運行時間的增加量級有關的時,就是在研究算法的漸進效率。也就是說,從極限角度看,只關心算法運行時間如何隨着輸入規模的無限增加而增加。函數
大O記號的定義爲:給定一個函數g(n),O(g(n)) = {f(n):存在正常數c和n0,使得對全部n>=n0,有0<=f(n)<=cg(n)}.O(g(n))表示一個函數集合,每每用該記號給出一個算法運行時間的漸進上屆。性能
判斷下面各式是否成立:spa
10n2+4n+2 = O(n2) -------- 成立code
10n2+4n+2 = O(n) -------- 不成立blog
(二)示例排序
一、下面這段代碼索引
1 def F(n): 2 sum = 0 3 i = 0 4 j = 1 5 sun = i + j 6 return sum
上面這段代碼的時間複雜度就是O(1),O(1)表示算法的執行時間老是常量(即一、二、三、四、5....10000行代碼的的執行時間都是 O(1),只要代碼的執行次數是常量,它的複雜度就是 O(1))class
二、下面這段代碼效率
1 def F(n): 2 sum = 0 3 for i in range(1,n+1): 4 sum = sum+i 5 return sum
假設第2行代碼的執行時間是1,那麼三、4行代碼都執行了N遍(一、二、3....n),因此代碼的執行時間是2n,代碼的總執行時間就是2n+1,根據前面的說明,在大O表示法中,咱們能夠忽略掉公式中的常量、低階項、高階項的係數,因此代碼的複雜度就是O(n)
三、 再看下面這段代碼:
1 def F(n): 2 sum = 0 3 for i in range(1,n+1): 4 for j in range(1,n+1): 5 sum = sum+i*j 6 return sum
假設第二行代碼執行時間是1,第3行執行時間是n,第四、5行的執行次數都是n2,因此執行時間是2n2。因此代碼總的執行時間是T(N) = 1+n+2n2,同理,這段代碼的時間複雜度是O(n2)
(三)總結下
總結一下,咱們這裏遇到下面三種狀況
一、O(1) -----常量階
O(1)表示算法的執行時間老是常量(即一、二、三、四、5....10000行代碼的的執行時間都是 O(1),只要代碼的執行次數是肯定的,它的執行次數就是 O(1))
二、O(n) -----線性階
O(n)表示一個算法的性能會隨着輸入數據n的大小變化而線性變化
三、O(n2) ----平方階
O(n2)表示一個算法的性能將會隨着輸入數據n的增加而呈現出二次增加
另外還有2個沒有說的就是對數(O(logN))和非多項式,非多項式這裏不考慮,對數階算法複雜度分析,下篇說明。
(四)分析插入排序、簡單選擇排序的算法複雜度
一、插入排序
1 #插入排序 2 def insertSort(A): 3 for i in range(len(A)): 4 key = A[i] 5 j = i -1 6 while A[j] > key and j >=0: 7 A[j+1] = A[j] 8 j -= 1 9 A[j+1] = key 10 return A
(1)假設第3行代碼的執行次數是n,那麼四、五、9行代碼的執行次數也是n,總共4n。
(2)第六、七、8行的執行次數就是n2(最壞的狀況),總共是3n2
(3)因此算法的執行次數爲 4n+3n2,即時間複雜度爲O(n2)
二、簡單選擇排序
1 def selectSort(A): 2 #迭代列表的前n-1個元素 3 for i in range(len(A)-1): 4 k = i 5 for j in range(i+1,len(A)): 6 if A[k] > A[j]: 7 k = j #更新最小值的索引 8 #若是A[i]不是最小值,交換A[i],A[k]的值 9 if k != i: 10 A[k],A[i] = A[i],A[k] 11 return A
同樣的道理,咱們只須要關注代碼執行次數最多的那段代碼就好了,即第5行代碼(n2),因此算法的時間複雜度也是O(n2)