接前面
连通图的最小生成树里面的克鲁斯卡尔算法应用并查集后简洁明了。
回顾
最小生成树就是把顶点边(数据结构)表示的生活中的连通图,改成树型数据结构表示的形式。并查集这种数据结构也可以表示树。有多的对比就选最好的。
普里姆算法
文章里先讲了普里姆算法。它是指定一个顶点开始生成树。还使用MST性质:最小权w的pu(堆顶的uv)一定在U和V-U构成的所有顶点的最小生成树中。依次找最小的边。比较起来Python的堆模块很简洁,只十行以内的代码。比书上的少多了,但也是帮助理解学习书上的内容。
克鲁斯卡尔算法
相比之下,克鲁斯卡尔算法就站在一个更高的高度,不用指定开始顶点。当然也是依据MST性质,生成的是同样的最小生成树。书上只给了算法的框架没有代码。前面文章也用并查集实现了,今天再复习一下并查集。
UnionFind
用指定长的列表学习模拟并查集的实现和操作。
class UnionFind:
def __init__(self, n):
self.up = list(range(n)) # 0 to n - 1 are the elements
self.rank = [0] * n
def find(self, x):
assert x < len(self.up)
if self.up[x] == x:
return x
else:
self.up[x] = self.find(self.up[x]) #Recursive call until x is found
return self.up[x]
def union(self, x, y):
repr_x = self.find(x)
repr_y = self.find(y)
if repr_x == repr_y:
return False #already in a same union
if self.rank[repr_x] == self.rank[repr_y]:
self.rank[repr_x] += 1
self.up[repr_y] = repr_x
elif self.rank[repr_x] > self.rank[repr_y]:
self.up[repr_y] = repr_x
else:
self.up[repr_x] = repr_y
return True
验证
'''
>>> a=UnionFind(10)
>>> a.find(5)
5
>>> a.find(9)
9
>>> a.union(5,9)
True
>>> a.find(4)
4
>>> a.find(5)
5
>>> a.find(9)
5
>>> print(a.rank)
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0]
>>> print(a.up)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 5]
>>> a.find(-1)
999
-1也是可以的,当成下标了。
'''
![]() |
---|
从验证来看,查找和合并的是下标,5、8、9都合到7,7的rank是1层。2、4合并后下标4的值改成了2,再与8合并后,7的rank就变成两层了。