测试下图中是否存在环
python代码实现
"""
并查集
"""
##### 查找节点node的根节点函数
def find_root(node, parent):
if parent[node] == -1: # node节点的父节点就是它自己时,说明它自己就是根节点
return node
else: # node的父节点不是就一层一层向上找父节点
return find_root(parent[node], parent)
##### 合并两个节点x,y的函数, 该函数返回1表示成功合并,返回0表示合并失败。
# 当合并的两个点正好在同一个集合里就会合并失败
def union(x, y, parent):
# 分别找x,y节点的根
x_root, y_root = find_root(x, parent), find_root(y, parent)
# 两节点的根不同,可合并;两节点的根相同会形成环,不可合并
if x_root == y_root:
return 0
else:
parent[x_root] = y_root
return 1
if __name__ == "__main__":
print("输入节点个数:")
n = int(input())
print("输入边条数:")
line_num = int(input())
# 6个节点的父节点列表的初始化
parent = [-1 for i in range(n)]
# parent = [1,4,1,4,-1,-1] 这三行试一试find_root递归写的对不对
# print(find_root(2, parent))
# print(find_root(4, parent))
#### 根据事例中的图写一段测试代码
edges = []
for times in range(line_num):
edges.append([int(i) for i in input().split(' ')])
# 以上获得所有输入信息
# 将所有信息添加到图中,合并节点,判断是否形成环
for line in edges:
x, y = line[0], line[1]
ans = union(x, y, parent)
if ans == 0:
print("Cycle detected!\n")
break
if ans == 1:
print("No cycle found.\n ")
"""
测试输入
6
6
0 1
1 2
1 3
2 5
2 4
3 4
另一测试例
6
5
0 1
1 2
1 3
2 5
3 4
"""
以上代码可能出现的问题:
在有这种长链时,查找parent会特别的慢
解决方法:
解决方法:将每个树的深度做一个记录,为了使合并的树越小越好,引入rank列表用来存放每个节点在其所在树的高度位置。我们将高度大的树的根节点作为高度小的树的根节点的父节点。
"""
并查集
"""
##### 查找节点node的根节点函数
def find_root(node, parent):
if parent[node] == -1: # node节点的父节点就是它自己时,说明它自己就是根节点
return node
else: # node的父节点不是就一层一层向上找父节点
return find_root(parent[node], parent)
##### 合并两个节点x,y的函数, 该函数返回1表示成功合并,返回0表示合并失败。
# 当合并的两个点正好在同一个集合里就会合并失败
def union(x, y, parent, rank):
# 分别找x,y节点的根
x_root, y_root = find_root(x, parent), find_root(y, parent)
# 两节点的根不同,可合并;两节点的根相同会形成环,不可合并
if x_root == y_root:
return 0
else:
# parent[x_root] = y_root 在拼接时不能直接拼接了,要加入rank比较
if rank[x_root] > rank[y_root]:
parent[y_root] = x_root
elif rank[x_root] < rank[y_root]:
parent[x_root] = y_root
else: # 两个相等的情况时,一个作为另一个的父节点,作为父节点的的深度需增加
parent[x_root] = y_root
rank[y_root] += 1
return 1
if __name__ == "__main__":
print("输入节点个数:")
n = int(input())
print("输入边条数:")
line_num = int(input())
# 6个节点的父节点列表的初始化
parent = [-1 for i in range(n)]
# parent = [1,4,1,4,-1,-1] 这三行试一试find_root递归写的对不对
# print(find_root(2, parent))
# print(find_root(4, parent))
# 添加一个rank列表,用来存放每个节点到该节点所在树的根节点的深度,初始化为0
rank = [0 for i in range(n)]
#### 根据事例中的图写一段测试代码
edges = []
for times in range(line_num):
edges.append([int(i) for i in input().split(' ')])
# 以上获得所有输入信息
# 将所有信息添加到图中,合并节点,判断是否形成环
for line in edges:
x, y = line[0], line[1]
ans = union(x, y, parent, rank)
if ans == 0:
print("Cycle detected!\n")
break
if ans == 1:
print("No cycle found.\n ")
"""
测试输入
6
6
0 1
1 2
1 3
2 5
2 4
3 4
另一测试例
6
5
0 1
1 2
1 3
2 5
3 4
"""