演算法複雜度分析(下)

2021-10-21 10:20:47 字數 2732 閱讀 4103

目錄

一、最好、最壞情況時間複雜度

二、平均情況時間複雜度

三、均攤時間複雜度

通過 演算法複雜度分析(上),我們掌握了大部分的演算法分析方法,本文將繼續講解四個複雜度分析方面的知識點:最好情況時間複雜度、最壞情況時間複雜度、平均情況時間複雜度、均攤時間複雜度。

我們來分析下面這段**的時間複雜度

function find(array, x) 

}return pos

}

上方**的目的是查詢array中是否存在x元素,如果存在,就返回1,沒有則返回-1,通過分析,我們可以知道上方**的複雜度為o(n),請中n為陣列長度(array.length)。

我們在陣列中查詢乙個資料,他可能在資料中的任何乙個位置,也可能不存在,所以我們可以對上述**進行優化(當找到時,跳出迴圈)。

function find2(array, x) 

}return pos

}

那麼經過優化,上方**的複雜度是多少呢?

如果陣列中的第乙個元素正好是要查詢的變數x,則時間複雜度是o(1),他代表在最理想的情況下,執行這段**的時間複雜度,我們稱之為最好情況時間複雜度

如果不存在變數x,則需要把陣列全都遍歷一遍,時間複雜度就是o(n),他代表在最糟糕的情況下,執行這段**的時間複雜度,我們稱之為最壞情況時間複雜度

最好情況時間複雜度和最壞情況時間複雜度對應的都是極端情況下的**複雜度,發生的概率其實並不大,為了更好的表示平均情況下的複雜度,我們需要引入乙個概念:平均情況時間複雜度。

平均時間複雜度怎麼分析呢?我們借助上面的例子:

我們要查詢變數x在陣列中的位置,一共有n+1(n為陣列長度)中情況(在陣列中:在陣列的 0 ~ n-1位置中,共有n種情況 ,不在陣列中:1種情況),我們把每種情況下,查詢需要遍歷的元素個數累加起來,然後再除以n+1,就可以得到需要遍歷的元素個數的平均值:(1+2+3+...+n+n)/(n+1) =n(n+3)/2(n+1)

這個結論雖然是正確的,但是計算過程稍微有點問題,因為n+1種情況,有著出現的概率的問題。

要查詢變數x,要麼在陣列中,要麼不在陣列中,這兩種真實的出現概率統計起來比較繁瑣,我們簡化下,假設在陣列中和不在陣列中的概率都是1/2,另外,要查詢到的資料出現在0 ~ n-1這n個位置的概率也是一樣的,為1/n,所以要查詢的資料出現在0 ~ n-1中任意位置的概率是1/(2n)。

當把出現的概率考慮進去後,上面的平均值公式就變為:1*(1/2n) + 2*(1/2n) + 3*(1/2n) + ... + n*(1/2n) + n*(1/2) =(3n+1)/4

上述結果用大o來表示,去掉係數和常量,最終的結果依然是o(n)。

我們來看下面的例子:

let array = new array(n); // n為任意數值,在此未知

let count = 0;

function insert(value)

array[0] = sum;

count = 1;

}array[count] = value;

count++;

}

上述**實現了乙個往陣列中插入資料的功能,當陣列滿了之後(count === array.length時),我們用for迴圈遍歷陣列求和,並清空陣列,將求和之後的sum值放到陣列的第乙個位置,然後再將資料插入,如果陣列一開始就是有空閒空間,則將資料插入陣列。

那麼上述**的時間複雜度是多少呢?我們先用剛才講到的三種時間複雜度分析方法來分析一下:

最理想情況下:陣列中有空閒空間,我們直接插入到下標為count的位置,所以最好情況時間複雜度是o(1)

最壞情況下,陣列中沒有空間了,我們需要先做一次遍歷求和,然後再將資料插入,所以最壞情況時間複雜度是o(n)

平均時間複雜度:陣列長度是n,根據資料插入的位置不同,我們可以分為n種情況,每種情況的時間複雜度是o(1),除此之外,在陣列沒有空閒的時候插入乙個資料,這時候的時間複雜度是o(n),這n+1種情況發生的概率相同,都是1/(n+1)。所以我們可以得到平均時間複雜度是:1*(1/(n+1)) + 1*(1/(n+1)) + 1*(1/(n+1)) + ...+n*(1/(n+1)) =o(1)(n個1/(n+1)相加,再加上額外的 n*(1/(n+1))情況,得到結果為2n/(n+1)  忽略掉係數和常數項,得到n/n = 1)。

接下來我們來看一下均攤時間複雜度的分析:

每一次o(n)的插入操作,都會跟著n-1次o(1)的插入操作,所以把耗時多的那次操作均攤到接下來的n-1次耗時少的操作上,均攤下來,這一組連續的操作的均攤時間複雜度就是o(1)。

均攤時間複雜度適應於以下場景:

對乙個資料結構進行一組連續操作中,大部分情況下時間複雜度都很低,只有個別情況下時間複雜度比較高,而且這些操作之間存在前後連貫的時序關係,這個時候,我們就可以將這一組操作放在一塊兒分析,看是否能將較高時間複雜度那次操作的耗時,平攤到其他那些時間複雜度比較低的操作上。而且,在能夠應用均攤時間複雜度分析的場合,一般均攤時間複雜度就等於最好情況時間複雜度。

部分參考:資料結構與演算法之美

演算法複雜度分析 下

在乙個陣列中查詢目標值x的 我們可以像下面這樣寫 int find int array,int x return pos 目標值x可能出現在陣列中的不同位置,也可能沒在陣列 現過 所以,不同情況下,這段 的時間複雜度是不一樣的。為了表示 在不同情況下的不同時間複雜度,我們需要引入三個概念 最好時間複...

複雜度分析(下)

最好 最壞時間複雜度分析 n 表示陣列 array 的長度 int find int array,int n,int x return pos 上面 的功能是在乙個陣列中查詢乙個變數x出現的位置,如果沒有找到,返回 1。這段 的時間複雜度應該為o n 其中n為數字的長度。但是我們在陣列中查詢資料,並...

演算法複雜度分析

分析非遞迴演算法效率的通用方案 1.決定用哪個 哪些 引數作為輸入規模的度量 2.找出演算法的基本操作 作為一規律,它總是位於演算法的最內層迴圈中 3.檢查基本操作的執行次數是否只依賴輸入規模。如果它還依賴一些其他的特性,則最差效率 平均效率以及最優效率 如果必要 需要分別研究。4.建立乙個演算法基...