图的连通性判断(并查集)_数据结构

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

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

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

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

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

具体代码如下:

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()