並差集-python版本
簡介
並查集,在一些有N個元素的集合應用問題中,我們通常是在開始時讓每個元素構成一個單元素的集合,然後按一定順序將屬於同一組的元素所在的集合合併,其間要反覆查找一個元素在哪個集合中。 --百度百科
應用
一些常見的用途有求連通子圖、求最小生成樹的 Kruskal 算法和求最近公共祖先(Least Common Ancestors, LCA)等。
基本操作
初始化
並查集的實現原理也比較簡單,就是使用樹來表示集合,樹的每個節點就表示集合中的一個元素,樹根對應的元素就是該集合的代表
圖中有兩棵樹,分別對應兩個集合,其中第一個集合爲$ {a,b,c,d}$,代表元素是 ;第二個集合爲 ,代表元素是 。
樹的節點表示集合中的元素,指針表示指向父節點的指針,根節點的指針指向自己,表示其沒有父節點。沿着每個節點的父節點不斷向上查找,最終就可以找到該樹的根節點,即該集合的代表元素。
# parent數組記錄該元素父節點的序號,size表示該樹高(以根節點計算)
class DSU:
def __init__(self, num):
self.parent = list(range(num))
self.size = [1] * num
查找根節點
通過遞歸的方式,進行查找該樹的根節點。如:find(d) -> a.
def find(self, x):
'''
查找x的父節點
:param x:
:return:
'''
if self.parent[x] != x:
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
求並集
在並集的時候,通過size數組記錄樹高,從而進行路徑壓縮。可以防止極端情況,如查找中的圖。
def union(self, x, y):
'''
合併x和y的集合
:param x:
:param y:
:return:
'''
x_root = self.find(x)
y_root = self.find(y)
if x_root == y_root:
return
# 根據樹高進行計算
if self.size[x_root] > self.size[y_root]:
# 將y合併到x
self.parent[y_root] = x_root
elif self.size[x_root] < self.size[y_root]:
self.parent[x_root] = y_root
else:
self.parent[x_root] = y_root # x拼接到y上
self.size[y_root] = self.size[y_root] + 1