演算法基礎 二 大O分析法 下

2021-09-21 14:21:39 字數 3302 閱讀 3398

同樣,我們先看一段**,你可以嘗試先自己分析一下它的時間複雜度:

//n 表示切片arrary的長度

func find(arrary int,n int,x int) (pos int) {

i := 0

pos := -1

for ;i可以看出來,這段**要事先的功能是,在乙個無序的切片中,查詢變數x出現的位置。如果沒有找到,就返回-1。

按照上次說的分析方法,這段**的複雜度是o(n),其中,n代表切片的長度。我們在陣列中查詢乙個資料,並不需要

每次都把整個陣列都遍歷一遍,因為可能中途找到就可以提前結束迴圈了。所以,我們可以把return放到if語句中去。

那麼問題來了,我們優化完之後,這段**的時間複雜度還是o(n)嗎?很顯然,我們上次學的內容解決不了這個問題。

因為根據x值的不同,該段**的時間複雜度也會不同。所以為了表示**在不同情況下的不同時間複雜度,我們需要引入

三個概念:最好情況時間複雜度、最壞時間複雜度和平均情況時間複雜度

顧名思義,最好情況時間複雜度就是,在最理想的情況下,執行這段**的時間複雜度,比如這個例子中,最理想

的情況就是要找的變數x正好是陣列的第乙個元素。

同理,最壞情況時間複雜度就是,在最糟糕的情況下,執行這段**的時間複雜度。比如,如果陣列中沒有要查詢的

變數x,我們需要把整個陣列都遍歷一遍才可以。

到此為止,你應該已經掌握了演算法複雜度分析的大部分內容了。下面我(作者)要給講乙個更加高階的概念,均攤時間複雜度,以

及它對應的分析方法,攤還分析(或者叫平攤分析)。均攤時間複雜度,聽起來跟平均時間複雜度有點像。對於初學者來說,這

兩個概念確實非常容易混淆。前面說了,大部分情況下,我們並不需要區分最好,最壞、平均三種複雜度。平均複雜度只在某些

特殊情況下才會用到,而均攤時間複雜度應用的場景比它更加特殊、更加有限。

老規矩,我(作者)還是借助乙個具體的例子來幫助你理解。(當然,這個例子只是我為了方便講解想出來的,實際上沒人會這麼寫。)

var count = 0

func insert(val,n int) {

array := make(int,n)

if count == cap(arrary) {

sum := 0

for i:=0;i這裡先來解釋一下這段**。這段**實現了乙個往陣列中插入資料的功能。當陣列滿了之後,也就是**中的count == cap(array)時,

我們用for迴圈遍歷陣列求和,並清空陣列,將求和之後的sum值放到陣列的第乙個位置,然後再將新的資料插入。如果陣列一開始就有空閒

空間,則直接將資料插入陣列。

那這段**的時間複雜度是多少呢?你可以先用我們剛講到的三種時間複雜度的分析方法來分析一下。最理想的情況下,陣列中有空閒空間,

我們只需要將資料插入到陣列下標為count的位置就可以了,所以最好情況時間複雜度為o(1)。最壞情況下,陣列中沒有空閒空間了,我們需

要先做一次陣列的遍歷求和,然後再將資料插入,所以最壞情況時間複雜度為o(n)。那平均時間複雜度是多少呢?答案是o(1)。我們還是可以

通過前面講的概率論的方法來分析。

假設陣列的長度是n,根據陣列插入的位置的不同,我們可以分為n種情況,每種情況的時間複雜度是o(1)。除此之外,還有一種「額外」的情況,

就是在陣列沒有空閒空間時插入乙個資料,這時候的時間複雜是o(n)。而且,這n+1種情況發生的概率一樣,都是1/(n+1)。所以,根據加權平均

的計算方法,我們求得的平均時間複雜度就是:

至此為止,前面的最好、最壞、平均時間複雜度的計算,理解綺裡啊應該都沒有問題。但是這個例子裡的平均複雜度分析其實並不需要那麼複雜,

不需要引入概率論的知識。這是為什麼呢?我們來對比一下這個insert()的例子和前面那個find()的例子,你就會發現這兩種有很大的差別。首先,

find()函式在極端情況下,複雜度才為o(1)。但是insert()在大部分情況下,時間複雜度都為o(1)。只有個別情況下,複雜度才比較高,為o(n)。

這是insert()第乙個區別於find()的地方。

我們再來看第二個不同的地方。對於insert()函式來說,o(1)時間複雜度的插入和o(n)時間複雜度的插入,出現的頻率是非常有規律的,而且

有一定的前後時序關係,一般都是乙個o(n)插入之後,緊跟著n-1個o(1)的插入操作,迴圈往復。所以,針對這樣一種特殊場景的複雜度分析,我們

並不需要像之前講平均複雜度分析方法那樣,找出所有的輸入情況及相應的發生概率,然後再計算加權平均值。

針對這種特殊的場景,我們引入了一種更加簡單的分析方法:攤還分析法,通過攤還分析得到的時間複雜度我們還起了乙個名字,叫做均攤時間

複雜度。均攤時間複雜度和攤還分析應用場景比較特殊,所有我們並不會經常用到。為了方便你理解、記憶,我這裡簡單總結一下它們的應用場景。如果

你遇到了,知道是怎麼回事就行了。

對乙個資料結構進行一組練習操作中,大部分情況下時間複雜度都很低,只有個別情況下時間複雜度比較高,而且這些操作之間存在前後連貫的時序關係,

這個時候,我們就可以將這一組操作放在一塊分析,看是否能夠將較高時間複雜度那次操作的耗時,平攤到其他那些時間複雜度比較低的操作上。而且,在

能夠應用均攤時間複雜度分析的場合,一般均攤時間複雜度就等於最好情況時間複雜度。同時,我(作者)認為:均攤時間複雜度就是一種特殊的平均時間

複雜度,我們沒有必要花太多的時間去區分它們。

今天我們學習了幾個複雜度分析的相關概念,分別有:最好情況時間複雜度、最壞時間複雜度、平均時間複雜度、均攤時間複雜度。之所以引入這幾個複雜度

概念,是因為:同一段**,在不同輸入的情況下,複雜度量級可能是不一樣的。

運用今天學習的知識,來分析一下下面這個add()函式的時間複雜度:

//全域性變數,大小為10的陣列array,長度len,下標i

var array = make(int,10)

var len = 10

var i = 0

//往陣列中新增乙個元素

func add(element int) {

for i>=len { //陣列空間不夠了

//重新申請乙個2倍大小的陣列空間

var new_array = make(int,2*len)

//把原來array陣列中的資料依次copy到new_array

for j:=0;j回答:最好:o(1);最壞:o(n);均攤:o(1)。

數模演算法 層次分析法

第一步 畫出層次結構圖 目標層準則層 方案層第二步 對於同一層次的各元素關於上一層次中某一準則的重要性進行兩兩比較,構造兩兩比較矩陣 判斷矩陣 一致性矩陣各行各列成倍數關係 第三步一致性檢驗 第四步 通過檢驗後 計算權重 算術平均法,幾何平均法,特徵值法 第五步,計算各層元素對系統目標的合成權重,並...

演算法分析 大O 大 大

在演算法的學習中,最開始便是要學習演算法的分析。學習演算法分析時,我們便會接觸到這麼幾個符號 大o 大 大 常常讓人難以理解。在通常的演算法分析時,我們可以明白,在輸入規模較小,各種演算法之間的時間消耗並無明顯差別。只有當輸入規模較大時,對各個演算法之間消耗差別的對比與分析才有意義。所以上面幾個符號...

演算法學習 大O表示法

上一節我們使用了兩種不同的方式來獲得兩個數的最大公約數,那麼如何判斷我們應該使用哪一種方式呢?這裡就涉及到了演算法的時間複雜度 空間複雜度 穩定性等幾個方面的因素,這次我們要討論的大o表示法就是用來表示時間複雜度。大o表示法法讓你能夠比較運算元,它指出了演算法執行時間的增速 演算法 在開始學習之前請...