1.並查集描述
一些有n
nn個元素的集合應用問題中,我們通常是在開始時讓每個元素構成乙個單元素的集合,然後按一定順序將屬於同一組的元素所在的集合合併,其間要反覆查詢乙個元素在哪個集合中。
為了快速解決這些問題,便有了並查集的概念。
並查集維護了乙個不相交的動態集的集合s1,
s2,⋯
,sns1
,s2
,⋯,
sn,每個集合將有乙個"首領"來標識該集合,我們不關心集合的哪個成員作為"首領"(不排除有些問題需要選擇適合特定規則的成員作為首領,例如最大成員做首領)。
2.並查集的三種操作
2.1 makeset(x) 初始化
以x為唯一成員和"首領"建立乙個新集合。
2.2 union(x,y) 合併
將"首領"為x和y的兩個集合進行合併,組成乙個新集合,新集合的"首領"可以是新集合的任何成員。
2.3 findset(x) 查詢
返回乙個指標,指向包含成員x的集合的"首領"。
2.4 例子
以下為例子,下劃線部分為"首領"。
初始化:,,,,,,
合併:,,
查詢:此時對c,d,e進行查詢操作將返回同樣的結果:d
合併:,
查詢:此時對a,b,c,d,e進行查詢操作將返回同樣的結果:d
查詢:此時對a,f進行查詢操作將返回不同的結果:d,f
3.並查集兩種結構
3.1 鏈式結構
3.2 樹結構
樹結構並查集由若干顆樹組成,樹的根結點為該集合的"首領",樹的每個結點只有乙個指向父節點的指標和乙個資料域。特別注意的是根結點的指標指向自己。
初始化:n
nn個只有根結點的樹。
合併:樹x和樹y合併,可使得樹y的根結點指向樹x的根結點即可完成合併。
查詢:對於元素xy,查詢其樹根結點即可,若樹根結點一樣,則xy在同乙個集合中。
1.按秩合併
1.1 秩的概念
為了更好的描述問題,引入"秩"的概念,某結點的秩是該結點的高度上界。
1.2 考慮如下情況:有n
nn個集合需要組合成乙個集合。
1)隨意合併,有可能使得每次合併都是乙個秩較大的樹掛載到秩較小的樹上,極端情況:
這樣,退化為乙個近似鍊錶。
2)按秩合併策略,每次都讓秩小的樹掛載到秩大的樹的根上。其最壞情況為,每次都選取相同高度的樹進行合併,這樣,將使得樹變成乙個近似的完全二叉樹。
顯然,完全二叉樹所有結點搜尋根結點的平均時間要小於鍊錶的時間。
很容易證明,在樹的高度不變的情況下的合併操作的攤還搜尋次數要小於加大樹高度的情況下的合併操作的攤還搜尋次數。
因此,我們希望合併操作時盡可能的不改變樹的深度。合併策略為:讓秩小的結點所在的樹成為秩較大結點所在的樹的子樹。而當兩個樹的深度一樣時,合併之後樹的深度不得不改變,因此仍然需要對秩進行維護。
2.路徑壓縮
為了盡快地找到根結點,減少查詢和合併操作的搜尋次數,從結點v搜尋到根結點時,我們可以將該結點及其所有祖先結點直接指向根結點,這樣一來,可以極大地減少那些結點到根結點的搜尋次數,這種方法稱為路徑壓縮。
3.效能
《演算法導論》對其效能進行詳細分析,結論為最壞執行時間為o(m
)α(n
)o(m)\alpha(n)
o(m)α(
n),其中m為所有操作(包括makeset,findset,union)的次數,而n為初始結點數。
α (n
)<
4\alpha(n)<4
α(n)
<
4,故可認為與m成線性關係。
1.維護的成員及建構函式
2.makeset(x) 初始化public
class
disjointset
}}
3.findset(x) 查詢+路徑壓縮public
void
makeset
(int x)
遞迴實現:
非遞迴實現:public
intfindset
(int x)
4.union(x,y) 按秩合併public
intfindset
(int x)
return x;
}
public
void
union
(int x,
int y)
private
void
link
(int x,
int y)
}
並查集 按秩合併 路徑壓縮
一種可以動態維護若干個不重疊的集合或無向圖的連通塊的資料結構。主要支援以下操作 find 查詢乙個元素屬於哪個集合 merge 合併兩個集合 並查集的每個集合都需要乙個 爹 來表示這整個集合,所以判斷兩個元素是否在同一集合,就看他們爹是否相同。有乙個顯而易見的初始化,對於要維護的序列,初始每個元素的...
並查集(路徑壓縮 按秩合併) 總結
就是連邊,然後,每次問你兩個點是否可互通。為無向邊 然後,暴力的話可能就是一條鏈下來,搞爆了。所以我們要想想優化。個人覺得這個比較好理解,很早便學會了,而且速度要優秀一些。就是將連了邊的同時指向乙個人 自擬的祖宗 然後,每次查詢的時候就壓縮一下路徑。具體是這樣來搞的 intgf int x intm...
BZOJ4668 冷戰 並查集 按秩合併
題意 還可以這樣亂搞 並查集按秩合併的好處 深度不會超過 o log n 樹的結構保持較穩定 雖說連邊的時候依舊是祖先來連邊,但連邊不會改變原來的結構,並且 u,v 路徑上會經過新連的邊 於是就可以亂搞了 維護乙個按秩合併的並查集,給連邊操作加時間戳,查詢的時候暴力求路徑上時間戳最大值 ps 暴力l...