程式猿必修課之資料結構(二)演算法和演算法的複雜度

2021-07-30 16:41:29 字數 2509 閱讀 7123

原文出自:

演算法是解決特定問題求解步驟的描述,在計算機中表現為指令的有限序列,並且每條指令表示乙個或多個操作。

演算法具有五個基本特性:輸入、輸出、有窮性、確定性、可行性。

好的演算法,應該具有:正確性、可讀性、健壯性、高效率和低儲存量的特徵。

輸入規模 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 記法。

用常數 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++)

int count = 1;

while (count < n)

由於每次 count 乘以 2 以後,就越來越接近於 n,也就是說有多少個 2 相乘後大於 n,則會退出迴圈。由 2x = n 等到 x = log2n。所以這個演算法的時間複雜度為 t(n) = o(logn)。

這是乙個迴圈巢狀的**。

int i, j;

for (i = 0; i < n; i++)

}

它的內迴圈我們已經知道,時間複雜度為 o(n),而對於外層的迴圈,不過是內部這個時間複雜度為 o(n) 的語句,再迴圈 n 次。所以這段**的時間複雜度為 o(n2)

如果外迴圈的次數改為了 m,時間複雜度就變為 o(m*n)。

int i, j, m;

for (i = 0; i < m; i++)

}

所以我們可以總結得出,迴圈的時間複雜度等於迴圈體的複雜度乘以該迴圈執行的次數。

下面這個迴圈巢狀,它的時間複雜度是多少呢?

int i, j;

for (i = 0; i < n; i++)

}

由於當 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 所佔儲存空間的函式。

程式猿必修課之資料結構(十)樹1

樹是一對多的資料結構 樹 tree 是 n n 0 個結點的有限集。n 0 時,稱為空樹。在任意一棵非空樹中 其實樹的定義用到了遞迴的方法。樹的每乙個結點包含乙個資料元素和若干個指向其子樹的分支。結點的度 結點擁有的子樹的個數稱為結點的度 degree 度為 0 的結點稱為葉結點 leaf 或終端結...

程式猿必修課之資料結構(七)棧2

斐波那契 fibonacci 是乙個經典的遞迴例子。數字 1,1,2,3,5,8,13.構成乙個序列,它的特點是 前面相鄰兩項之和是後一項的值。用數學函式來定義是 斐波那契數列 用遞迴實現列印出前 40 位的斐波那契數列數的 如下 includeint fbi int int main return...

程式猿必修課之資料結構(八)佇列

佇列 queue 是只允許在一端進行插入操作,而在另一端進行刪除操作的線性表。佇列是一種先進先出 first in first out 的線性表,簡稱fifo。允許插入的一端稱為隊尾,允許刪除的一端稱為隊頭。佇列是特殊的線性表,因此它的各種操作類似線性表,不同的是插入資料只能在隊尾進行,刪除資料只能...