前言
當你編寫完一個程序的時候,怎樣對它進行算法最優的判斷呢?效率又是怎樣體現的呢?效率=總執行次數/總時間,一般來說,程序越龐大,其執行效率越低。因此,對於模塊化程序,優化其算法的時間復雜度是非常重要的。
定義
我們把一個算法中的語句執行次數定義為頻度,算法的運行時間刻畫為一個函數,定義為 T(n) ,其中n稱為問題的規模,當n不斷變化時,T(n)也隨之變化。但我們想知道n與T(n)之間的大致規律,所以我們引入漸進符號 O 來刻畫算法的運行時間。
現在我們編寫一個程序,把其中表示算法運行時間的函數記為 T(n)。對於一個給定的函數 g(n),有 O(g(n)) = {f(n) | 存在常量 c, n0, c>0, n0>0, 使得對所有 n ≥ n0, 有0 ≤ f(n) ≤ c·g(n)},記作 f(n) = O(g(n)) 。如下圖。注意這個等號並不是左右相等,而是代表集合論中的 “∈”,表示 'is a ..' 的關系,如“ n = O(n2) ”。當我們說運行時間為 O(g(n)) 時,表示存在一個O(g(n)) 的函數 f(n),使得 n 不管輸入什么值時,T(n) 的上界都是 f(n)。所以 O(g(n)) 表示最壞情況運行時間。
通常,我們稱 O(g(n)) 為時間復雜度。
圖(a) f(n) = O(g(n))
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
// do .....
}
}






下面拿幾道題練練手:
(1)
for(i=1;i<=n;i++) for(j=1;j<=n;j++) s++; //循環了n*n次,當然是O(n^2)
(2)
for(i=1;i<=n;i++) for(j=i;j<=n;j++) s++; //循環了(n+n-1+n-2+...+1)≈(n^2)/2,因為時間復雜度是不考慮系數的,所以也是O(n^2)
(3)
for(i=1;i<=n;i++) for(j=1;j<=i;j++) s++; //循環了(1+2+3+...+n)≈(n^2)/2,當然也是O(n^2)
(4)
i=1;k=0; while(i<=n-1){ k+=10*i; i++; } //循環了n-1≈n次,所以是O(n)
(5)
for(i=1;i<=n;i++) for(j=1;j<=i;j++) for(k=1;k<=j;k++) x=x+1; //循環了(1^2+2^2+3^2+...+n^2)=n(n+1)(2n+1)/6(這個公式要記住哦)≈(n^3)/3,不考慮系數,自然是O(n^3)
需要注意的是,在時間復雜度中,log(2,n)(以2為底)與lg(n)(以10為底)是等價的,因為對數換底公式:
在各種不同算法中,若算法中語句執行次數為一個常數,則時間復雜度為O(1),譬如簡單的求和,代碼如下,其頻度為3,O(1)
int a,b; //頻度為2 printf("%d",a+b); //頻度為1 return 0;
實踐出真知,下面放一些更難的例題,幫助理解與計算時間復雜度



while(n!=0)
{
n/=10;
}
while(n!=0)
{
n=n/2;
}
void func(int n) { int i=0,s=0; while(s<n) { i++; s=s+i; } }
時間復雜度O(n^(1/2))
解析:
測試樣例: n = 3,5,9,...n^2 ,可得頻度 N = 2,3,4,...n^(1/2) (近似計算)
則運行時間 T(n) = c*(n^(1/2)) + c2 (c, c2為常數),可得時間復雜度 O(n^(1/2))x=91; y=100; while(y>0) { if(x>100) { x=x-10; y--; } else x++; }