并查集
在计算机科学中,并查集是一种树型的数据结构,用于处理一些不交集(Disjoint Sets)的合并及查询问题。
有一个联合-查找算法(Union-find Algorithm)定义了两个用于此数据结构的操作:
Find:确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集。
Union:将两个子集合并成同一个集合。
由于支持这两种操作,一个不相交集也常被称为联合-查找数据结构(Union-find Data Structure)或合并-查找集合(Merge-find Set)。
为了更加精确的定义这些方法,需要定义如何表示集合。一种常用的策略是为每个集合选定一个固定的元素,称为代表,以表示整个集合。接着,
Find(x) 返回 x所属集合的代表,而 Union 使用两个集合的代表作为参数。
并查集可以判断各节点的连通性,可以解决欧拉回路等问题
Python版并查集代码如下所示:
class UnionFindSet(object): def __init__(self, nodes): ''' 初始化并查集 :param nodes: 传入的数据 ''' # 记录每个节点的父节点 self.fatherMap = {} # 每个门派集合的信息 self.eachMap ={} # 初始化, 每个节点自成一派 for node in nodes: self.fatherMap[node] = node def findFather(self, node): ''' 递归逻辑:返回当前节点的父节点; base case:当前节点的父节点是自己 :param node: :return: ''' father = self.fatherMap[node] if (node != father): father = self.findFather(father) # 超级优化: 路径压缩 self.fatherMap[node] = father return father def isSameSet(self, a, b): ''' 判断两个节点a和b是否属于同一门派 :param a: :param b: :return: ''' return self.findFather(a) == self.findFather(b) def union(self, a, b): ''' 合并a所在的门派和b所在的门派 :param a: :param b: :return: ''' if a is None or b is None: return # a的掌门 aFather = self.findFather(a) # b的掌门 bFather = self.findFather(b) self.fatherMap[aFather] = bFather def EachSet(self, nodes): ''' 记录每个门派集合的信息 Args: nodes: Returns: ''' EachSet_father = [] for i in range(len(nodes)): if self.fatherMap[nodes[i]] == nodes[i]: EachSet_father.append(nodes[i]) for ele in EachSet_father: self.eachMap[ele] = [] for node in nodes: if self.findFather(node) == ele: self.eachMap[ele].append(node) if __name__ == '__main__': nodes = ['张三丰', '宋远桥', '张翠山', '宋青书', '张无忌', '阳顶天', '杨逍', '金毛狮王', '紫衫龙王', '白眉鹰王', '青翼蝠王', '郭靖', '杨康', '杨过', '洪七公', '黄蓉', '黄药师'] union_find = UnionFindSet(nodes) union_find.union('张三丰', '宋远桥') union_find.union('宋远桥', '宋青书') union_find.union('张三丰', '张翠山') union_find.union('张翠山', '张无忌') # union_find.union('张无忌', '金毛狮王') union_find.union('阳顶天', '杨逍') union_find.union('阳顶天', '金毛狮王') union_find.union('阳顶天', '紫衫龙王') union_find.union('阳顶天', '白眉鹰王') union_find.union('阳顶天', '青翼蝠王') # union_find.union('郭靖', '阳顶天') union_find.union('郭靖', '杨康') union_find.union('郭靖', '黄蓉') union_find.union('杨康', '杨过') union_find.union('黄蓉', '洪七公') union_find.union('黄蓉', '黄药师') # 判断洪七公与张三丰是否有联系 print(union_find.isSameSet('洪七公', '张三丰')) # 显示每个集合情况 union_find.EachSet(nodes) print(union_find.eachMap)