數據-第4課-審判程序的靈魂
第4課-審判程序的靈魂
- 算法效率的度量
l 事後統計法
比較不同算法對同一組輸入數據的運行處理時間.
缺陷:
(1) 為了獲得不同算法的運行時間必須編寫相應程序.
(2) 運行時間嚴重依賴硬件以及運行時的環境因素.
(3) 算法的測試數據的選取相當困難。
事後統計法雖然直觀,但是實施困難且缺陷多 ,但是實施困難且缺陷多,一般不予考慮。
l 事前分析估算
依據統計的方法對算法效率進行估算。
l 影響算法效率的主要因素
(1) 算法采用的策略和方法。
(2) 問題的輸入規模。
(3) 編譯器所產生的代碼。
(4) 計算機執行速度。
算法效率的簡單估算
- 算法效率的估量
例子:二重循環估算
#include <stdio.h>
int func(int a[], int len)
{
int i = 0;
int j = 0;
int s = 0;
for(i=0; i<len; i++)
{
for(j=0; j<len; j++)
{
s += i*j;
}
}
return s;
}
int main()
{
int array[] = {1, 2, 3, 4, 5};
printf("%d\n", func(array, 5));
return 0;
}
估算時間:t = (n2 + 2) T
啟示
(1) 練習中的程序關鍵部分的操作數量為n*n。
(2) 三種求和算法中求和的關鍵部分的操作數量分別為2n, n和1。
隨著問題規模n的增大,它們操作數量的差異也會越來越大,因此實際算法在時間效率上也會變得非常明顯!
不同算法操作數量的對比
判斷一個算法的效率時,往往只需要關註操作數量的最高次項,其它次要項和常數項可以忽略。
l 大O表示法
(1) 算法效率嚴重依賴於操作(Operation)數量。
(2) 在判斷時首先關註操作數量的最高次項。
(3) 操作數量的估算可以作為時間復雜度的估算。
O(5) = O(1)
O(2n + 1) = O(2n) = O(n)
O(n2 + n + 1) = O(n2)
O(3n3+1) = O(3n3) = O(n3)
常見時間復雜度類型
關系:O(1) < O(logn) < O(n) < O(nlogn) < o(n2) < O(n3) < O(2n) < O(n!) < O(nn)
- 最好與最壞
例子:
#include <stdio.h>
int search(int array[], int length, int n)
{
int ret = -1;
int i = 0;
for(i=0; i<length; i++)
{
if( array[i] == n )
{
ret = i;
break;
}
}
return ret;
}
int main()
{
int array[5] = {1, 2, 3, 4, 5};
printf("%d\n", search(array, 5, 1)); //O(1),一次就好
printf("%d\n", search(array, 5, 5)); //O(n),n次才好
return 0;
}
意義:
當算法在最壞情況下仍然能滿足需求時,可以推斷,算法的最好情況和平均情況都滿足需求。
在沒有特殊說明時,我們所分析的算法的時間復雜度都是指最壞時間復雜度。
- 算法的空間復雜度
算法的空間復雜度通過計算算法的存儲空間實現
S(n) = S(n) = ) =O(f(n))
其中,n為問題規模,f(n)為在問題規模為n時所占用存儲空間的函數。
空間復雜度表示申請的空間大小,大O表示法同樣適用於算法的空間復雜度。當算法執行時所需要的空間是常數時,空間復雜度為O(1),為n時是O(n)。
- 空間與時間的策略
(1) 多數情況下,算法執行時所用的時間更令人關註。
(2) 如果有必要,可以通過增加空間復雜度來降低時間復雜度。
(3) 同理,也可以通過增加時間復雜度來降低空間復雜度。
l 在實現算法時需要分析具體問題對執行時間和空間的要求。
例子:
#include <stdio.h>
/*
問題:
在一個由自然數1-1000中某些數字所組成的數組中,每個數字可能出現零次或者多次。
設計一個算法,找出出現次數最多的數字。
*/
void search(int a[], int len)
{
int sp[1000] = {0};
int i = 0;
int max = 0;
for(i=0; i<len; i++)
{
int index = a[i] - 1;
sp[index]++;
}
for(i=0; i<1000; i++)
{
if( max < sp[i] )
{
max = sp[i];
}
}
for(i=0; i<1000; i++)
{
if( max == sp[i] )
{
printf("%d\n", i+1);
}
}
}
int main()
{
int array[] = {1, 1, 3, 4, 5, 6, 6, 6, 2, 3};
search(array, sizeof(array)/sizeof(*array));
return 0;
}
這個算法很好。
思考:
當兩個算法的大O表示法相同的時候,是否意味著兩個算 ,是否意味著兩個算法的效率完全相同?
數據-第4課-審判程序的靈魂