并查集

在计算机科学中,并查集是一种树型的数据结构,用于处理一些不交集(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)

 

posted on 2019-07-09 18:45  天池怪侠  阅读(165)  评论(0编辑  收藏  举报

导航