并查集判断图的连通

判断图的连通性判断方法比较多,最常见的就是并查集、DFS、BFS 这几种,网上的代码也很多,文章最后也给出了一些参考,这里主要讲一讲并查集。

因为有判断有向图中是否存在欧拉路径的需求,需要先判断有向图的基图是否连通,于是就找了一些算法,有了这篇文章,文章偏向于个人的理解与想法,深入了解可以点解参考。

并查集由一个记录节点的根节点的数组(或者类似容器,字典)和两个函数(find, join)构成。容器(数组)记录了每个点的根节点是哪个,函数 find 用于查找某个节点的根节点,join 函数是合并两个具有相连关系的节点。

先看代码:

pre = {}


def find(x):
    r = x
    while pre[r] != r:
        r = pre[r]
    i = x
    while i != r:  # 路径压缩,平衡树层次的效果
        j = pre[i]
        pre[i] = j
        i = j
    return r


def join(x, y):
    fx = find(x)
    fy = find(y)
    if fx != fy:
        # root = min(fx, fy)  # 平衡树的层次的效果
        # pre[fx] = root
        # pre[fy] = root
        pre[fx] = fy


def judge(n, edges):
    '''
    判断是否连通
    :param n: 节点数
    :param edges: 边的集合
    :return: 是否连通
    >>> judge(4, [(0, 1), (2, 0),(2, 3)])
    True
    >>> judge(4, [(2, 0),(2, 3)])
    False
    '''
    for i in range(n):
        pre[i] = i
    for i in range(len(edges)):
        join(edges[i][0], edges[i][1])
    group = 0
    for i in range(n):
        if pre[i] == i:
            group += 1
    if group == 1:
        return True
    else:
        return False


if __name__ == '__main__':
    import doctest
    doctest.testmod()

思路为:对于图中的每个节点,设定它的根节点为它本身。对图中的每一条边的两个端点进行合并操作,得到的结果就是相互连通的节点的根节点指向同一个节点。所以只要查询一下结果中节点的根节点等于其本身的节点的数目就可以知道这个图被分成连通的几个部分,如果连通,则为 1。

pre 字典中保存着每个节点的根节点,find 开始之前要初始化。find 函数经过一层层的寻找,最终找到 x 的根节点,返回。join 函数对边的两个端点所属的集合做合并,如果两个节点的根节点不同,则通过指定其中一个根节点作为另一个根节点的父节点,达到合并所属集合的效果。

最终只需要判断 pre 中本身为本身的父节点的顶点数目即可判断连通性。路径压缩和父节点选择是一种平衡整个关系树的层次的方法,自己体会。

参考:
EOJ 1816 判断图连通的三种方法——dfs,bfs,并查集
无向图的连通性问题(并查集)
超有爱的并查集~

你可能感兴趣的:(并查集判断图的连通)