在進行算法分析時,語句總的執行次數 T(n) 是關於問題的規模n 的函數,進而分析 T(n) 隨 n 的變化狀況並肯定 T(n) 的數量級,算法的時間複雜度,也就是算法的時間度量,記做:T(n) = O(f( ))。它表示隨問題的規模 n 的增大,算法的執行時間的增加率 f(n) 的增加率相同,稱做算法的漸近時間複雜度,簡稱爲時間的複雜度,其中 f(n) 是問題規模n的某個函數。算法
這樣用大寫 [ O( ) ] 來體現算法時間複雜度的記法,咱們就稱之爲大O記法。例如:O(n)、O(1)、O(n2)、O(log n) 等等。通常狀況下,隨着 n 的增大,T(n) 增加最慢的算法爲最優算法。數據結構
1,用時間1取代運算時間中的全部加法常數。函數
2,在修改後的運行的函數中,只保留最高階項。spa
3,若是最高階項存在且不是1,則去除與這個項相乘的常數。獲得的結果就是大O階。code
1 int sum = 0, n = 100; /* 執行一次 */
2 sum = (1+n) *n/2; /* 執行一次 */
3 printf("the sum is:%d",sum); /* 執行一次 */
咱們能夠看出運行次數的函數是 f(n) = 3。根據咱們上面的大O階公式 1 能夠獲得,把常數項 3 改成 1,在保留最高階時發現沒有最高階項,因此時間複雜度爲大 O(1)。也就是說,不管算法是 3 次仍是 30 次,哪怕是 300 次,這些只要是常數項,它的時間複雜度都爲大 O(1),而不是O(3)、O(30)、O(300)。即咱們稱之爲常數階。blog
1 for(int i = 0; i < n; i++) { 2 sum += i; 3 }
從上面的這段代碼咱們能夠看出,它的時間複雜度爲O(n),由於循環體中的代碼須要執行n次。排序
1 for(int i = 0; i < n; i++) {
2 for(int j = i; j < n; j++) {
3 //時間複雜度爲O(n2)
4 }
5 }
分析:class
當 i = 0時,內循環執行了 n 次,效率
當 i = 1時,內循環執行了 n-1 次,循環
......
當 i = n-1時。執行了 1 次,
因此總的執行次數爲:n = (n-1)+(n-2)+ ··· + 1= n(n+1)/2 = n2/2+n/2。
由上面的公式可得:第一條代碼中沒有加法常數項,不考慮;第二條只保留最高階項,所以保留 n2/2;第三條去除這個項相乘的常數,因此去除了 1/2;最終咱們獲得的代碼段時間複雜度就是 O(n2)。
1 int count = 1; 2 while (count < n) { 3 count *= 2; 4 }
上面代碼咱們能夠看出,count = count * 2 以後就距離 n 更近一步,也就是說,有多少個 2 相乘後大於 n,就退出循環。因此咱們能夠由 2x = n 推導出 x = log2n ,像這樣的循環時間複雜度,咱們就稱爲對數階的複雜度即爲 O(log n)。
數據結構中咱們通常經常使用的時間複雜度表示有:O(1)、O(n)、O(n2)、O(log n)、O(nlog n)、O(n3)、O(2n)。
按時間複雜度所耗費的時間從大到小排序依次爲:
O(1) < O(log n) < O(n) < O(nlog n) < O(n2) < O(n3) < O(2n)