演算法 第四版 之並查集 union find演算法

2022-08-24 10:48:12 字數 3017 閱讀 6743

開個新坑, 準備學習演算法(第四版), 並把上面學到的東西寫成部落格, 畢竟以前也學過一點演算法, 但效果甚微

並查集, 在這本書的第一章1.5中叫做union-find演算法, 但在其他地方這個叫做並查集,就是說一系列點的連通問題,比如, 我們有十個點, 分別記作0~9:

加入我們要把2和4連線起來怎麼表示呢? 首先我們會想到,給所有的點標上乙個號, 來代表他們的連通關係, 我們初始化這個數就是他們id本身:

如果我們要連線2和4, 就使得4的id為2:

之後要連線間隔點任意兩個點, 就把它們和它們相應的點的值都設定為一樣就行了, 如果我們要比對這兩個是是否連通, 也只要比較他們的值是否相等就行了.

我們可以很輕易的寫出下面的**:

1/*2

* 並查集實現程式3*/

4public

class

uf 13 count =n;14}

1516

public

void union( int p, int q)

25 count--; //

連通圖數減126}

2728

public

int find(int i)

3132

public

boolean connected(int p, int q)

3536

public

int getcount()

3940 }

這就是樹上的quick-find演算法. 但是, 問題來了, 這樣我們查詢兩個點是否連通很方便, 速度很快, 但是連線兩個點就很慢了--我們需要遍歷所有的點! 在例子中我們只有十個點, 可是若有幾百萬個點呢? 每操作一次就遍歷上百萬個點, 這樣我們的**肯定就會無比的慢, 所以, 我們必須想新的辦法.

這是, 我們有了新的方法,就是書上的quick-union演算法, 就是說, 我們每次連線兩個點時, 只改變乙個點的標識值, 也就形成了一棵棵樹, 這樣在乙個連通圖中就肯定有乙個值的標識值是它本身的id, 沒有發生改變, 當我們用查詢find()方法查詢時,只要一直往下找, 直到找到標識值為它本身的這個點就行, 這樣就不會每次都遍歷到所有的點,  總體上來說時間複雜度就降下來了:

我們也可以輕易地寫出相應的**:

1

public

void union( int p, int q) else

13 count--;14}

1516

public

int find(int i)

但是, 還不夠, 因為我們得考慮最壞的情況, 就是當我們形成的這棵數沒有分支, 也就是形成了一條鏈時, 我們就依然變成了需要遍歷所有的點, 這樣, 我們辛辛苦苦降下去的複雜度有回來了

然後, 我們就有了書上的加權的quick-union演算法, 就是將樹的高度記錄下來, 然後每次union()時把高度低的數加到高度高的樹上去, 這樣樹的高度就不會超過lgn, 時間複雜度也控制在了o(lgn), **如下:

1/*2

* 並查集實現程式3*/

4public

class

uf 16 count =n;17}

1819

public

void union( int p, int q) else

31 count--;32}

3334

public

int find(int i)

3940

public

boolean connected(int p, int q)

4344

public

intgetcount()

4748 }

當然, 我們再有辦法優化, 我們的目標當然是無限接近常數次操作, 也就是o(1), 雖然這是不可能的. 那麼, 我們還能怎麼優化呢? 這就是,路徑壓縮, 就是說在呼叫find()方法時同時加乙個迴圈, 將所有的這些點直接指向根節點, 這樣我們下次操作這些點不就是常數次操作了嘛! **如下:

1

public

int find(int i)

10return

i;11 }

在最後, 附送下最後的完整**:

1/*2

* 並查集實現程式

3* 使用路徑壓縮的加權quit-union演算法4*/

5public

class

uf 17 count =n;18}

1920

public

void union( int p, int q) else

32 count--;33}

3435

public

int find(int i)

44return

i;45}46

47public

boolean connected(int p, int

q) 50

51public

intgetcount()

5455 }

完成!

演算法 第四版 之堆排序

堆排序是建立在堆的基礎上的,了解堆排序我們得先了解二叉堆.二叉堆是以二叉樹為基礎的,當一棵二叉樹的每個結點都大於等於它的兩個子節點數時,它被稱為堆有序.我們可以很容易的理解出,它的根節點是最大節點 二叉堆可以用指標和陣列兩種方式表示,本文用的是陣列的方式.我們在堆中有兩種操作方法,一種叫做上浮,一種...

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

本書對排序類演算法有乙個模板,包括了以下幾種方法 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...