Algorithms——Union-Find
并查集(Union-Find)问题:研究动态连接性
基础算法:快速查找(Quick Find)、快速连接(Quick Union)
提升算法:带权的并查集(Weighted Union Find)、路径压缩后带权的并查集(Weighted Union Find with Path Compression)
快速查找(Quick Find):维护数组id[i],i代表各个连接单位,不同索引id[i]相同时代表这一系列i属于同一连通风量。若id[1]=id[2]=id[4],则1、2、4三个单位处于同一连通分量,即1、2、4互相连接。
快速连接(Quick Union):利用数组id[i],维护森林,所有相连的单位处于同一棵树内,连接(Union)使得两颗不同的树合并为一棵树。id[i]的值为i的父亲,如果id[i]=i则i为i所处的树的根(root)。每当一棵树并入另一棵树,将并入树的根改为待并入树的根。
带权的并查集(Weighted Union Find):改善Quick-Union,额外维护数组sz[i],存储根为i的树的所有结点量/权。当两棵树合并时,比较两棵树的权,权较小的树并入权较大的树。改善的目的是使得在树中较少出现“一枝独秀”。树的深度不超过lgN,每当叶子的深度增加时,该树最少并入相同大小的树,此时深度+1,若共有N个节点,则最多可以进行lgN次合并,使得所有节点处于同一颗树,该树深度最大,一次合并深度增加1。
路径压缩后带权的并查集(Weighted Union Find with Path Compression):改善Weighted Union Find,相比带权并查集并不维护额外的数组。当每一次进行并、查操作时,尽量使得当前节点直接指向根(root),示例代码中仅仅使查询节点指向其爷爷。
算法复杂度: Python示例代码:
Quick-Find:
class QF:
id = []
count = 0
def __init__(self, n):
self.id = list(range(n))
self.count = n
def union(self, p, q):
if self.connected(p,q):
pass
else:
old_p = self.id[p]
for i in range(self.count):
if self.id[i] == old_p:
self.id[i] = self.id[q]
def connected(self, p, q):
if self.id[p] == self.id[q]:
return 1
return 0
Quick-Union:
class QU:
id = []
count = 0
def __init__(self, n):
self.id = list(range(n))
self.count = n
def root(self, p):
while p != self.id[p]:
p = self.id[p]
return p
def union(self, p, q):
if self.connected(p,q):
pass
else:
self.id[self.root(p)] = self.root(q)
def connected(self, p, q):
if self.root(p) == self.root(q):
return 1
return 0
Weighted Union Find:
class WQU:
id = []
sz = []
count = 0
def __init__(self, n):
self.id = list(range(n))
self.sz = [1] * n
self.count = n
def root(self, p):
while p != self.id[p]:
p = self.id[p]
return p
def union(self, p, q):
if self.connected(p,q):
pass
else:
rootp = self.root(p)
rootq = self.root(q)
if self.sz[rootp] >= self.sz[rootq]:
self.id[rootq] = rootp
self.sz[rootp] += self.sz[rootq]
else:
self.id[rootp] = rootq
self.sz[rootq] += self.sz[rootp]
def connected(self, p, q):
if self.root(p) == self.root(q):
return 1
return 0
Weighted Union Find With Compression:
class WQUPC:
id = []
sz = []
count = 0
def __init__(self, n):
self.id = list(range(n))
self.sz = [1] * n
self.count = n
def root(self, p):
while p != self.id[p]:
self.id[p] = self.id[self.id[p]]
p = self.id[p]
return p
def union(self, p, q):
if self.connected(p,q):
pass
else:
rootp = self.root(p)
rootq = self.root(q)
if self.sz[rootp] >= self.sz[rootq]:
self.id[rootq] = rootp
self.sz[rootp] += self.sz[rootq]
else:
self.id[rootp] = rootq
self.sz[rootq] += self.sz[rootp]
def connected(self, p, q):
if self.root(p) == self.root(q):
return 1
return 0
C语言示例代码: