前言
主要記錄四個復雜度分析知識點:
- 最好情況時間復雜度 (best case time complexity)
- 最壞情況時間復雜度 (worst case time complexity)
- 平均情況時間復雜度 (average case time complexity)
- 均攤時間復雜度 (amortized time complexity)
李柱明博客:https://www.cnblogs.com/lizhuming/p/15487280.html
最好、最壞情況時間復雜度
最好情況時間復雜度就是,在最理想的情況下,執行這段代碼的時間復雜度 。
最壞情況時間復雜度就是,在最糟糕的情況下,執行這段代碼的時間復雜度 。
例子:在一個鏈表中找出合適的節點:
- 最好:遍歷該鏈表時,第一個就合適了,那時間復雜度為 O(1)。
- 最壞:遍歷該鏈表時,全遍歷了,那時間復雜度就為 O(n)。
平均情況時間復雜度
最好和最壞的情況都是極端的,出現的概率不高。
通用的就算平均情況時間復雜度。
計算方法
把每一種情況的時間復雜度全部加起來再除以情況總數。
若考慮每種情況的概率,那就把每種情況的時間復雜度都乘以當前情況的概率然后再除以情況總數。
分析過程
分析遍歷鏈表這個例子(看到最后)
假設鏈表長度為 n,情況有 n+1 種:n 種在鏈表不同位置和一種不在鏈表中。
按照平均時間復雜度的計算方法得出以下結果:
按照大 O 表示法,忽略掉系數、低階和常量,得出的平均時間復雜度為 O(n)。
上述方法並不是很准確,因為每種情況出現的概率並不一樣,若把各種情況發生的概率也考慮進去,分析過程為
假設在數組中與不在數組中的概率都為 1/2。
數據出現在 0~n-1 這 n 個位置的概率也是一樣的,為 1/n。
這個值就是概率論中的 加權平均值 ,也叫作 期望值 ,所以平均時間復雜度的全稱應該叫加權平均時間復雜度或者 期望時間復雜度 。
使用大 O 表示法,其時間復雜度是 O(n)。
均攤時間復雜度
大部分情況下,我們並不需要區分最好、最壞、平均三種復雜度。
平均復雜度只在某些特殊情況下才會用到,而均攤時間復雜度應用的場景比它更加特殊、更加有限。
例子
// array 表示一個長度為 n 的數組
// 代碼中的 array.length 就等於 n
int[] array = new int[n];
int count = 0;
void insert(int val)
{
if (count == array.length)
{
int sum = 0;
for (int i = 0; i < array.length; ++i)
{
sum = sum + array[i];
}
array[0] = sum;
count = 1;
}
array[count] = val;
++count;
}
通過代碼分析得:
-
功能:把所有傳入的數值求和保存到
array[0]
- 把 val 值保存到 array 數組中。
- 當數組放滿以后,把數組 array 中已使用空間的各值總和保存到
array[0]
,然后重新開始。
該函數的時間復雜度分析
-
最好:O(1):
- 在 array 數組還有可用空間時。
-
最壞:O(n):
- 在 array 數組沒有可用空間時。
-
平均:O(1):
- 每種情況的概率出現都一樣,即是不用考慮概率論。
- 未滿時每種情況的時間復雜度為 O(1);共 n 種。
- 滿時情況的時間復雜度為 O(n);共 1 種。
- (O(1)*n+O(n)) /(n+1)= O(1)
-
均攤:O(1):
- 由於這個例子的各種情況的出現是有規律的:n-1 次 O(1) 后會出現一次 O(n) 。按照這種情況,可以把這一次 O(n) 均攤到前面的 n-1 次中,即是每種情況都加上 O(n)/(n-1) = O(1) 。
均攤的應用場景
由於只有在特殊的情況下才使用到均攤,所以列出一些常用的場景即可。如下:
對一個數據結構進行一組連續操作中,大部分情況下時間復雜度都很低,只有個別情況下時間復雜度比較高,而且這些操作之間存在前后連貫的時序關系。
這個時候,我們就可以將這一組操作放在一塊兒分析,看是否能將較高時間復雜度那次操作的耗時,平攤到其他那些時間復雜度比較低的操作上。
在能夠應用均攤時間復雜度分析的場合,一般均攤時間復雜度就等於最好情況時間復雜度。