博客主要參考:https://baike.so.com/doc/6119935-6333082.html
1.概念與運用
並查集是一種樹型的數據結構,用於處理一些不相交集合(Disjoint Sets)的合併及查詢問題,常常在使用中以森林來表示。主要運用在查找無向圖的連通性問題上(連通分支個數問題、種類問題等),不管如何出現,只要可以抽象成無向圖的連通性問題,均可以運用。
2.具體實例
實例來自飄過的小牛中的博客:
話說江湖上散落着各式各樣的大俠,有上千個之多。他們沒有什麼正當職業,整天揹着劍在外面走來走去,碰到和自己不是一路人的,就免不了要打一架。但大俠們有一個優點就是講義氣,絕對不打自己的朋友。而且他們信奉“朋友的朋友就是我的朋友”,只要是能通過朋友關係串聯起來的,不管拐了多少個彎,都認爲是自己人。這樣一來,江湖上就形成了一個一個的幫派,通過兩兩之間的朋友關係串聯起來。而不在同一個幫派的人,無論如何都無法通過朋友關係連起來,於是就可以放心往死了打。但是兩個原本互不相識的人,如何判斷是否屬於一個朋友圈呢?
我們可以在每個朋友圈內推舉出一個比較有名望的人,作爲該圈子的代表人物。這樣,每個圈子就可以這樣命名“中國同胞隊”美國同胞隊”……兩人只要互相對一下自己的隊長是不是同一個人,就可以確定敵友關係了。
但是還有問題啊,大俠們只知道自己直接的朋友是誰,很多人壓根就不認識隊長要判斷自己的隊長是誰,只能漫無目的的通過朋友的朋友關係問下去:“你是不是隊長?你是不是隊長?”這樣,想打一架得先問個幾十年,餓都餓死了,受不了。這樣一來,隊長面子上也掛不住了,不僅效率太低,還有可能陷入無限循環中。於是隊長下令,重新組隊。隊內所有人實行分等級制度,形成樹狀結構,我隊長就是根節點,下面分別是二級隊員、三級隊員。每個人只要記住自己的上級是誰就行了。遇到判斷敵友的時候,只要一層層向上問,直到最高層,就可以在短時間內確定隊長是誰了。由於我們關心的只是兩個人之間是否是一個幫派的,至於他們是如何通過朋友關係相關聯的,以及每個圈子內部的結構是怎樣的,甚至隊長是誰,都不重要了。所以我們可以放任隊長隨意重新組隊,只要不搞錯敵友關係就好了。於是,門派產生了。
3.具體實現(固定)
//在地圖上給你若干個城鎮,這些城鎮都可以看作點,然後告訴你哪些對城鎮之間是有道路直接相連的。最後要解決的是整幅圖的連通性問題。輸入數據如下:
//第一行:4 2
//第二行:1 3
//第三行:4 3
//第一行告訴你,一共有4個點,2條路。下面兩行告訴你,1、3之間有條路,4、3之間有條路
class solution{
int getRoot(vector<int> nums, int root){
int son = root;
while (root != nums[root]){ //查找根節點
root = nums[root];
}
while (son != root){ //路徑壓縮
int t = nums[son]; //直接根節點
nums[son] = root;
son = t;
}
return root;
}
int buildConnection(int n, int m, vector<vector<int>> edges){ //參數取決於題目,這裏假設是無向圖的連通問題
vector<int> nums(n);
for (int i = 0; i < n; ++i) nums[i] = i;
for (auto edge: edges){
int a = getRoot(nums, edge[0]);
int b = getRoot(nums, edge[1]);
if (a != b){
nums[a] = b;
}
}
}
}
路徑壓縮是特別重要的,可以解決快速查找根節點的問題:
[1]https://blog.csdn.net/niushuai666/article/details/6662911