演算法第四版的一些小問題

2021-09-11 10:43:21 字數 1482 閱讀 7622

union-find演算法用於檢測動態連通性,例如計算機網路中的兩個節點是否連通,在乙個特定圈子裡的兩個人是否有間接的朋友關係,等等。

quick-find演算法是union-find演算法的眾多實現中最簡單也最沒有效率的一種,它的主要實現如下:

public int find(int p) 

public void union(int p, int q)

// 執行到這裡,說明 p 和 q 不在相同的分量中,因此需要把它們進行歸併,在這裡,是把 p 所在的分量裡的所有元素全部重新命名為 q 所在的分量裡的名稱(唯一)

for (int i = 0; i < id.length; i++)

} count--;

}

find() 函式用於查詢乙個點 p 的名稱;union() 函式用於歸併兩個點 p 和 q,如果它們已經在同乙個連通分量裡,那麼不會產生任何歸併效果。

之所以把這種演算法叫quick-find,是因為它的 find() 操作很快,只需要訪問id陣列一次;但是quick-find的 union() 操作卻很慢,因為它需要訪問整個id陣列。

事實上,union() 訪問陣列的次數,至少是 n+3,至多是 2n+1,其中n是點的個數。

這是怎麼算出來的呢?下面來看一下。

union() 函式一開始的兩個 find() 操作無論如何是逃不掉的,所以這裡至少就訪問了 2 次id陣列。

而 if (pid == qid) 這一句,沒有對陣列進行任何訪問,因此,最後的for迴圈應該是至少訪問了 n+1 次數組,但這又是怎麼算出來的呢?

i 從 0 迴圈到 id.length(即n),共執行了n次,所以for迴圈裡的if語句一定會執行n次,所以陣列訪問至少會有n次,那麼還差1次,是怎麼來的呢?

由於一定有乙個 i 使得 id[i] == pid 成立(也就是p所在的那個分量),所以 id[i] == qid 至少會被執行一次,所以for迴圈訪問陣列的次數就至少是 n+1 次了。在這種情況下,所有id陣列中,只有乙個元素是與p處於同一連通分量的(其實也就是p這乙個,或者說,p很「孤獨」),它會被合併到q所在的連通分量中。

那麼union() 訪問陣列的次數,最多是 2n+1,這又是怎麼算出來的呢?

當id陣列中,除了q之外,其他所有元素都與p處於同一連通分量中的話,那麼,if (id[i] == pid) 這個條件就會成立 n-1 次,這意味著 id[i] = qid 會被執行 n-1 次,而n次 if 判斷無論如何都是會被執行的,所以for迴圈裡訪問陣列的次數是 n+n-1=2n-1 次,另外前面說了,union()函式中兩個find()操作是免不了的,所以還要再加2次,總共是 2n-1+2=2n+1 次。

因此,union()訪問陣列的次數在 n+3 到 2n+1 之間。

如果所有的 n 個分量其實都在乙個連通分量中,那麼在解這個union-find問題的時候,就要呼叫 n-1 次union()函式,則需要訪問陣列的次數至少是 (n+3)(n-1) 次,即等價於 n^2 次的複雜度。

於是得證。

《演算法(第四版)》排序 模板

本書對排序類演算法有乙個模板,包括了以下幾種方法 1 sort 這個方法裡面實現的就是排序的演算法 2 less 這個方法裡是利用了comparable介面裡的compareto方法,其中compareto方法對於本物件與傳入的比較物件小於,等於,大於,分別返回負數,0,正數 這個方法如果compa...

演算法 第四版 練習1 4 2

修改threesum,正確處理兩個較大的int值相加可能溢位的情況 首先jdk中定義int佔4個位元組,32位 後面全部的計算都是以此為根據的 32位就是jvm僅僅給分配32個格仔的空間,用以存放資料。總所周知計算機中用0和1存放資料。那麼,32個格仔中放滿0或1的方法 有2的32次方種 或者說32...

演算法(第四版)1 4摘抄

我們會使用數學分析為演算法成本建立簡潔模型並使用實驗資料驗證這些模型。一 第乙個挑戰是 決定如何定量測量程式的執行時間?一般來說,數學模型中的對數項是不能忽略的,但在倍率假設中它在 效能的公式中的作用並不那麼重要。對於編寫的每個程式,你都需要能夠回答這個基本問題 該程式能在可接受的時間內處理這些資料...