算法的時間複雜度定義爲:算法
在進行算法分析時,語句總的執行次數T(n)是關於問題規模n的函數,進而分析T(n)隨n的變化狀況並肯定T(n)的數量級。算法的時間複雜度,也就是算法的時間量度,記做:T(n}=0(f(n))。它表示隨問題規模n的增大,算法執行時間的埔長率和 f(n)的埔長率相同,稱做算法的漸近時間複雜度,簡稱爲時間複雜度。其中f( n)是問題規橫n的某個函數。數據結構
這樣用大寫O()來體現算法時間複雜度的記法,咱們稱之爲大O記法。通常狀況下,隨着n的增大,T(n)增加最慢的算法爲最優算法。
以前咱們說的三個求和算法的時間複雜度分別爲0(n),0(1),0(n2)。我就推一下吧。
計算 1 + 2 + 3 + 4 + ...... + 100。代碼以下,以前也有講過:函數
int main()
{
int i, sum = 0, n = 100; /* 執行1次 /
for( i = 1; i <= n; i++) / 執行 n+1 次 /
{
sum = sum + i; / 執行n次 /
//printf("%d \n", sum);
}
printf("%d", sum); / 執行1次 */
}
從代碼附加的註釋能夠看到全部代碼都執行了多少次。那麼這寫代碼語句執行次數的總和就能夠理解爲是該算法計算出結果所須要的時間。該算法所用的時間(算法語句執行的總次數)爲: 1 + ( n + 1 ) + n + 1 = 2n + 3性能
而當 n 不斷增大,好比咱們此次所要計算的不是 1 + 2 + 3 + 4 + ...... + 100 = ? 而是 1 + 2 + 3 + 4 + ...... + n = ?其中 n 是一個十分大的數字,那麼因而可知,上述算法的執行總次數(所需時間)會隨着 n 的增大而增長,可是在 for 循環之外的語句並不受 n 的規模影響(永遠都只執行一次)。因此咱們能夠將上述算法的執行總次數簡單的記作: 2n 或者簡記 n設計
這樣咱們就獲得了咱們設計的算法的時間複雜度,咱們把它記做: O(n)code
再來看看高斯的算法:io
int main()
{
int sum = 0, n = 100; /* 執行1次 /
sum = (1 + n) n/2; /* 執行1次 */性能分析
printf("%d", sum); /* 執行1次 */
}
這個算法的時間複雜度: O(3),但通常記做 O(1)。效率
從感官上咱們就不難看出,從算法的效率上看,O(3) < O(n) 的,因此高斯的算法更快,更優秀。數據結構與算法
下面再來一個例子:
int main()
{
int i, j, x = 0, sum = 0, n = 100; /* 執行1次 /
for( i = 1; i <= n; i++)
{
sum = sum + i;
//printf("%d \n", sum);
for( j = 1; j <= n; j++)
{
x++; / 執行nn次 /
sum = sum + x;
}
}
printf("%d", sum); /* 執行1次 */
}
上面的代碼嚴格的說不能稱之爲一個算法,畢竟它很「無聊並且莫名其妙」(畢竟算法是爲了解決問題而設計的嘛),先不論這個「算法」能解決什麼問題,咱們看一下它的「大O階」如何推導,仍是先計算一下它的執行總次數:
執行總次數 = 1 + (n + 1) + n(n + 1) + nn + (n + 1) + 1 = 2n2 + 3n + 3
如何推導大o階呢?咱們給出了下面 的推導方法:
用常數1取代運行時間中的全部加法常數。
在修改後的運行次數函數中,只保留最髙階項。
若是最高階項存在且不是1,則去除與這個項相乘的常數。
按照上面推導「大O階」的步驟咱們先來第一步:「用常數 1 取代運行時間中的全部加法常數」,則上面的算式變爲:執行總次數 = 2n^2 + 3n + 1
第二步:「在修改後的運行次數函數中,只保留最高階項」。這裏的最高階是 n 的二次方,因此算式變爲:執行總次數 = 2n^2
第三步:「若是最高階項存在且不是 1 ,則去除與這個項相乘的常數」。這裏 n 的二次方不是 1 因此要去除這個項的相乘常數,算式變爲:執行總次數 = n^2
所以最後咱們獲得上面那段代碼的算法時間複雜度表示爲: O( n^2 )
最後咱們在把常見的算法時間複雜度以及他們在效率上的高低順序記錄在這裏,是你們對算法的效率有個直觀的認識。
O(1) 常數階 < O(logn) 對數階 < O(n) 線性階 < O(nlogn) < O(n^2) 平方階 < O(n^3) < { O(2^n) < O(n!) < O(n^n) }
最後三項用大括號把他們括起來是想要告訴你們,若是往後你們設計的算法推導出的「大O階」是大括號中的這幾位,那麼趁早放棄這個算法,在去研究新的算法出來吧。由於大括號中的這幾位即使是在 n 的規模比較小的狀況下仍然要耗費大量的時間,算法的時間複雜度大的離譜,基本上就是「不可用狀態」。
延伸閱讀
此文章所在專題列表以下:
第一話:你的數據結構怎麼學的? 第二話:數據結構的歷史與來由 第三話:關於數據結構的一些概念 第四話:數據的邏輯結構 第五話:數據的物理結構 第六話:關於數據類型 第七話:抽象數據類型ADT 第八話:補充數據結構基本概念的關係 第九話:數據結構與算法的關係 第10話:什麼是算法? 第11話:算法的五個基本特徵 第12話:什麼樣的算法纔是好算法 第13話:算法的性能分析 第14話:如何計算算法的時間複雜度 第15話:算法的最壞狀況與平均狀況 第16話:算法的空間複雜度