引子
最近再來回顧一下算法相關的知識,那自然,首先要學習的就是 時間複雜度的概念,以及其計算方式。下面,我就會簡單地介紹下時間複雜度,以及會給出幾道典型的時間複雜度計算題。
時間複雜度
將算法中基本操作的執行次數作爲算法時間複雜度。
常見時間複雜度的大小比較關係:
下面,我將給出幾個簡單的算法,並計算其時間複雜度。
算法案例
案例一
public void fun(int n) {
int i = 1, j = 100;
while (i < n) {
++j;
i += 2;
}
}
求上述算法的時間複雜度。
這個算法很簡單,顯然問題的規模爲n,基本語句爲 i += 2;。我們假設循環進行了 m 次後停止。此時,我們可以得到:
1 + 2m + K = n。其中K是一個常量,可能爲0,也可能爲1,用於修正結果值。因爲在循環結束時,i 可能等於 n,也可能等於 n-1。
上面式子最終解得:。
也就是說,上述算法的時間複雜度 T(n) = O(n)。
案例二
public void fun(int n) {
int i, j, x = 0;
for (i = 1; i < n; ++i) {
for (j = i + 1; j <= n; ++j) {
++x;
}
}
}
這個算法也很簡單,算法的規模爲n,基本語句爲 ++x;。簡單的分析下,我們很容易得到:
對於每一個符合條件的 i,++x; 執行的次數爲 n - (i + 1) + 1 = n - i 次。
則 ++x; 執行的總次數爲:
顯而易見,上述算法的時間複雜度。
案例三
public void fun(int n) {
int i = 0, s = 0;
while (s < n) {
++i;
s += i;
}
}
上述算法問題的規模爲n,基本語句爲 ++i; 和 s += i; 兩句。
對於這個問題,我假設 循環經過 m 次結束,s的值爲S(m)。則我們很容易得到:
- 當 m = 1 時,S(1) = 1;
- 當 m = 2 時,S(2) = S(1) + 2 = 1 + 2;
- 當 m = 3 時,S(3) = S(2) + 3 = 1 + 2 + 3;
- 由上可得:
循環經過m次後停止,此時有 S(m) + K = n。K用於修正結果。即:
我們將其解出,得到結果:
上面的是個錯誤值,我們直接將其捨棄。所以,該算法的基本語句執行的次數爲:
顯而易見,該算法的時間複雜度 。
案例四
public void mergeSort(int i, int j) {
int m = 0;
if (i != j) {
m = (i + j) / 2;
mergeSort(i, m);
mergeSort(m + 1, j);
}
merge(i, j, m);
}
已知下面的條件:
- 調用該方法時,是通過 mergeSort(1, n) 來調用該方法的。
- merge() 方法的時間複雜度爲 O(n)。
求 該算法的時間複雜度。
首先,我們來理解一下該方法。該方法實際的邏輯可以理解是,將需要排序的集合二等分爲兩份,分別進行排序。
比如,假設我們給定一個例子,i = 1,j = 20,意味着我們將對一個含有20個元素的集合進行排序。在 mergeSort() 方法中,會將該集合分爲兩個集合,第一個集合是 下標從1到10,第二個集合是下標從 11到20。所以,如果我們設定 mergeSort() 方法的基本操作次數爲 f(n),則 mergeSort() 方法內部的 mergeSort() 方法的基本操作次數就是 。
有了上面的理解,我們就能夠進行推理:
已知 merge() 方法的時間複雜度爲 O(n),我們假設 merge() 方法的基本操作次數爲 a·n。
我們假設mergeSort()方法的基本操作次數爲 f(n)。我們可以得出:
①;
當 時,代入①式有:
②;
將 ② 式帶入 ① 式,得到:
③;
又有當 時,代入①式有:
④;
將 ④ 式帶入 ③ 式,得到:
⑤;
同樣,我們分別再求、...、,綜合上面①、③、⑤式,可以得到:
也就是說, ⑥。
然後,從 mergeSort() 方法我們可以得出 f(1) = O(1) ⑦ 。
這裏,根據 ⑦ 式,我們想辦法化掉 ,則當 時,有
這裏,兩個式子結合,替換掉k,則可以得到mergeSort()方法的基本操作次數爲:
顯然,mergeSort()方法的時間複雜度 。
案例五
具有 n 個元素的順序表,如上圖,分析其插入和刪除一個元素的時間複雜度。
對於上面這個順序表,假設其是一個數組。我們分析其插入一個元素時,需要移動元素的平均個數。這裏,我們分兩步進行分析:
首先,求概率。
總有 n 個元素,則其總共有 n + 1 個插入點。每個位置被插入的可能性相同,則每一個未知被插入概率爲:。
然後,求元素移動個數。
假設要把新元素插入到第 i 個元素之後(如果在1號元素之前插入,則記做在 0 號元素之後插入),則需要將第 i 號元素之後的所有元素向後移動1位,移動元素的個數爲:n - i 。
所以,移動元素個數的期望爲:
顯然,平均要移動一半的元素,插入算法的時間複雜度T(n) = O(n),刪除算法也是一樣爲O(n)。
總結
算法是程序員的內功心法,而時間複雜度又是算法學習的基石。時間複雜度的計算牽涉到的數學知識很多,準備最近趕緊複習一下數學了~
參考文章
1、《數據結構高分筆記》2016版,率輝 主編。