算法
算法是解決特定問題求解步驟的描述,在計算機中表現爲指令的有限序列,並且每條指令表示一個或多個操作。
算法的特性
算法具有五個基本特性:輸入、輸出、有窮性、確定性、可行性。
算法設計的要求
好的算法,應該具有:正確性、可讀性、健壯性、高效率和低存儲量的特徵。
函數的漸近增長
輸入規模 n 在沒有限制的情況下,只要超過一個數值 N, 這個函數就總是大於另一個函數,我們稱函數是漸近增長的。
給定兩個函數 f(n) 和 g(n), 如果存在一個整數 N,使得對於所有的 n > N, f(n) 總是比 g(n) 大,那麼我們說 f(n) 的增長漸近快於 g(n)。
算法時間複雜度
在進行算法分析時,語句總的執行次數 T(n) 是關於問題規模 n 的函數,進而分析 T(n) 隨 n 的變化情況並確定 T(n) 的數量級。算法的時間複雜度,也就是算法的時間量度,記作:T(n) = O(f(n))。它表示隨問題規模 n 的增大,算法執行時間的增長率和 f(n) 的增長率相同,稱爲算法的漸近時間複雜度,簡稱爲時間複雜度。其中 f(n) 是規模 n 的某個函數。
用 O() 來體現算法時間複雜度的記法,叫作大 O 記法。
推導大 O 階方法
- 用常數 1 取代運行時間中的所有加法常數。
- 在修改後的運行次數函數中,只保留最高階項。
- 如果最高階項存在且不是 1 ,則去除與這個項相乘的常數。
常數階
高斯算法
int sum = 0, n = 100; // 執行 1 次
sum = (1 + n) * n / 2; // 執行 1 次
printf("%d", sum); // 執行 1 次
這個算法的運行次數函數是 f(n) = 3。根據推導大 O 階的方法,第一步把常數項 3 改爲 1。第二步保留最高階項,它沒有最高階項,所以這個算法的時間複雜度爲 T(n) = O(1)。
當 n = 1 時,算法執行次數爲 3, 當 n = 100時,算法的執行次數還是 3,所以我們可以看出這個算法的執行次數與 n 的規模沒關係。我們把這種與問題的大小(n 的大小)無關,執行時間恆定的算法, 叫作常數階。
對於分支結構,無論是真還是假,執行的次數都是恆定的,不會隨着 n 的變化而變化,所以單純的分支結構(不包含在循環結構中),其時間複雜度也是 O(1)。
線性階
下面這段代碼的時間複雜度爲 O(n),因爲循環體中的代碼必須要執行 n 次。
int i;
for (i = 0; i < n; i++) {
/* 時間複雜度爲 O(1) 的程序步驟序列 */
}
對數階
int count = 1;
while (count < n) {
count = count * 2;
/* 時間複雜度爲 O(1) 的程序步驟序列 */
}
由於每次 count 乘以 2 以後,就越來越接近於 n,也就是說有多少個 2 相乘後大於 n,則會退出循環。由 2x = n 等到 x = log2n。所以這個算法的時間複雜度爲 T(n) = O(logn)。
平方階
這是一個循環嵌套的代碼。
int i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
/* 時間複雜度爲 O(1) 的程序步驟序列 */
}
}
它的內循環我們已經知道,時間複雜度爲 O(n),而對於外層的循環,不過是內部這個時間複雜度爲 O(n) 的語句,再循環 n 次。所以這段代碼的時間複雜度爲 O(n2)
如果外循環的次數改爲了 m,時間複雜度就變爲 O(m*n)。
int i, j, m;
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
/* 時間複雜度爲 O(1) 的程序步驟序列 */
}
}
所以我們可以總結得出,循環的時間複雜度等於循環體的複雜度乘以該循環運行的次數。
下面這個循環嵌套,它的時間複雜度是多少呢?
int i, j;
for (i = 0; i < n; i++) {
for (j = i; j < n; j++) { // 注意 j = i 而不是 0
/* 時間複雜度爲 O(1) 的程序步驟序列 */
}
}
由於當 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。
用我們推導大 O 階的方法,第一條,沒有加法常數不考慮;第二條,只保留最高階項,因此保留 n2/2;第三條,去除這個項相乘的常數,也就是去除 1/2, 最終這個算法的時間複雜度爲 T(n) = O(n2)
常見的時間複雜度
階 | 非正式術語 |
---|---|
O(1) | 常數階 |
O(n) | 線性階 |
O(n2) | 平方階 |
O(logn) | 對數階 |
O(nlogn) | nlogn階 |
O(n3) | 立方階 |
O(2n) | 指數階 |
常用的時間複雜度所耗費的時間從小到大依次是:
O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < O(nn)
算法空間複雜度
算法的空間複雜度通過計算算法所需的存儲空間實現,算法空間複雜度的計算公式:S(n) = O(f(n)),其中 n 爲問題的規模,f(n)爲語句關於 n 所佔存儲空間的函數。
總結
- 算法是解決特定問題求解步驟的描述,在計算機中爲指令的有限序列,並且每條指令表示一個或多個操作。
- 算法的特性:有窮性、確定性、可行性、輸入、輸出。
- 算法的設計要求:正確性、可讀性、健壯性、高效率和低存儲量需求。
作者:Xiao_Mai
鏈接:https://www.jianshu.com/p/d72d4c9e90c6
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯繫作者獲得授權並註明出處。