轉載: http://www.nowamagic.net/librarys/veda/detail/2195
在進行算法分析時,語句總的執行次數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。代碼如下,之前也有講過:
-
#include "stdio.h" 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)
再來看看高斯的算法:
#include "stdio.h"
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) 的,所以高斯的算法更快,更優秀。
下面再來一個例子:
#include "stdio.h"
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++; /* 執行n*n次 */
sum = sum + x;
}
}
printf("%d", sum); /* 執行1次 */
}
上面的代碼嚴格的說不能稱之爲一個算法,畢竟它很“無聊而且莫名其妙”(畢竟算法是爲了解決問題而設計的嘛),先不論這個“算法”能解決什麼問題,我們看一下它的“大O階”如何推導,還是先計算一下它的執行總次數:
執行總次數 = 1 + (n + 1) + n*(n + 1) + n*n + (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) }