資料結構與演算法之並查集

2021-08-22 02:30:02 字數 3019 閱讀 3585

並查集結構可以用於:

(1)檢查兩個元素是否屬於同乙個集合:

比如對於圖1這個例子來說,如果我們想要檢查節點d和節點e是否屬於同乙個集合,可以這樣操作:

d節點往上找其父節點,一直往上找,直到某個節點的父節點是其本身,此時停止(找到了節點a);

e節點也按照相同的步驟往上找其父節點,找到節點a;

如果這兩個節點往上找到的最終父節點相同,那麼可以說它們是屬於同乙個集合的。

(2)可以把兩個元素各自屬於的集合合併在一起:

比如對於圖2這個例子,怎樣將兩個集合合併在一起呢?

首先我們算一下集合1中節點的個數,是3。然後我們再計算集合2中的節點個數,是2。哪乙個集合的元素個數少,就把那個集合掛接在集合元素個數多的集合上面。

首先我們先定義乙個節點的類:

public static class node 

}

然後開始定義並查集結構:

public static class unionfindset 

// 這裡給出的節點是儲存在list裡面的

public void makeset(listnodes)

} // 這個函式用於尋找某個節點的最終節點(遞迴版本)

public node findheadrecur(node node)

node father = fathermap.get(node);

if (father != node)

fathermap.put(node, father);

return father;

} // 非遞迴版本findhead函式,這個很清晰,就是模擬了遞迴過程入棧和出棧的過程

public node findheadnonrecur(node node)

stackstack = new stack();

node cur = node;

node father = null;

father = fathermap.get(cur);

while (cur != father)

fathermap.put(cur, father);

while (!stack.isempty())

return father;

} // 看兩個元素是否屬於同乙個集合,只需要看它們的父節點是否為同乙個節點

public boolean issameset(node a, node b)

// 合併兩個集合,看集合的元素個數

public void union(node a, node b)

node afather = findheadrecur(a);

node bfather = findheadrecur(b);

if (afather != bfather) else

}} }

並查集可以延伸至島問題的求解

什麼是島問題?下面先介紹一下島問題的基本解法,之後會延伸出使用並查集來解決分塊矩陣的島問題

比如,乙個矩陣只有0和1兩種值,每個位置都可以和自己的上下左右四個位置相連。如果有一片1連在一起,則這個部分稱為乙個島。問,給定乙個矩陣,求這個矩陣中有多少個島?

比如給定的矩陣是這樣的:

可以看到,這個矩陣的島的數量是3個。

可以使用乙個感染函式遞迴地求解,感染函式每次遇到乙個1,都將其變成2,然後在看這個1的上下左右有沒有1,有的話也標記為2,這樣就不會重複地計算已經統計過的1了。

列出**:

public static int containsisland(int matrix) 

} return res; }

// 感染函式

public static void infect(int matrix, int m, int n, int i, int j)

matrix[i][j] = 2;

// 遞迴

infect(matrix, m, n, i + 1, j);

infect(matrix, m, n, i, j + 1);

infect(matrix, m, n, i - 1, j);

infect(matrix, m, n, i, j - 1);

}

這個解法適用於矩陣不是很大的情況。

如果矩陣很大,我們可以將矩陣分塊,先分別計算每乙個分塊兒矩陣中島的數量,以及需要留意它們的邊界資訊。

對於矩陣1,它有2兩個島;對於矩陣2,它也有兩個島。所以島的數量暫時先為4個。

然後,比較兩個矩陣相鄰邊界的資訊,如圖5中藍色部分。

對於過程1:相鄰部分都為1,且a與c之前並沒有合併過(並查集),可以合併(使用並查集中的union方法),此時島的數量 = 4 - 1 = 3。

對於過程2:相鄰部分都為1,但是a與c之前合併過(並查集中的issameset方法),此時島的數量不變。

對於過程3:相鄰部分有0,跳過。

對於過程4,相鄰部分都為1,且b與c之前並沒有合併過(並查集),可以合併(使用並查集中的union方法),此時島的數量 = 3 - 1 = 2。

過程5與過程3相同。

所以最終島的總數為2。

以上是我對演算法學習的乙個歸納與總結,水平有限望理解,如有錯誤請指出。

參考:左程雲《演算法班課程》

資料結構與演算法之並查集

並查集 union find 是一種高效的資料結構,主要的操作有 為方便敘述,把所有元素視作點,元素之間的關係視作線,存在聯絡便存在關係 需要注意的是,這裡的關係應當是1.自反的,2.對稱的,3.傳遞的 所謂合併,便是將兩個點之間 畫 一條線。又上邊的定義不難理解相連的若干點之間互相存在關係,這樣我...

演算法基礎之資料結構 並查集

題目 合併計算 一共有 n 個數,編號是 1 n,最開始每個數各自在乙個集合中。現在要進行 m 個操作,操作共有兩種 m a b,將編號為 a 和 b 的兩個數所在的集合合併,如果兩個數已經在同乙個集合中,則忽略這個操作 q a b,詢問編號為 a 和 b 的兩個數是否在同乙個集合中 輸入格式 第一...

資料結構之並查集

並查集 union find sets 是一種簡單的用途廣泛的集合.並查集是若干個不相交集合,能夠實現較快的合併和判斷元素所在集合的操作,應用很多,如其求無向圖的連通分量個數 最小公共祖先 帶限制的作業排序,還有最完美的應用 實現kruskar演算法求最小生成樹。其實,這一部分 演算法導論 講的很精...