数据结构之并查集:路径压缩继续优化并查集——20

路径压缩继续优化并查集

在实现的并查集中,在合并操作merge(item1, item2)时,会不管两个元素所在的分组大小,总是将item
1的分组合并到item2的分组,这样可能会导致树的深度无必要地增加:
在这里插入图片描述
如果是大树合并到小树上,会导致树的深度增加,进而造成增删改查等操作的代价增大
因此我们要对并查集的合并操作进行优化。

优化合并方式

  • 每次合并时,都将小分组的元素往大分组合并,由于本例初始化都是一个元素,对应一个分组,它合并的情况可能会变成如下这样(箭头代表分组之间的edge),类似一颗星状的树:
    在这里插入图片描述
属性和方法说明
  1. self.num_groups 分组数量
  2. self.groups 一个数组,索引代表传入的item的值,元素代表分组编号
  3. nums_in_each_group 一个数组,索引代表分组编号,元素代表每个分组的元素个数
  4. count_groups() 获取当前总共分数的数量
  5. in_the_same_group(item1, item2) 判断两个传入的item是否在同一分组
  6. which_group(item) 获取传入的item的所在分组
  7. unite(item1, item2) 合并两个元素到同一分组,小的分组总是会往大的分组合并
Python代码实现及测试
class UF_Tree_Weighted:
    def __init__(self, n):
        self.num_groups = n
        self.groups = [i for i in range(n)]
        self.nums_in_each_group = [1 for _ in range(n)]

    def count_groups(self):
        return self.num_groups

    def in_the_same_group(self, item1, item2):
        return self.which_group(item1) == self.which_group(item2)

    def which_group(self, item):
        """Find item's root------>groups[groups[groups[...groups[item]...]]]"""
        while self.groups[item] != item:
            item = self.groups[item]
        return item

    def unite(self, item1, item2):
        p = self.which_group(item1)
        q = self.which_group(item2)
        if p == q:
            return
        if self.nums_in_each_group[p] <= self.nums_in_each_group[q]:
            # Merge the smaller group into the bigger's
            self.nums_in_each_group[q] += self.nums_in_each_group[p]
            self.nums_in_each_group[p] = 0
            # Change the smaller group-number to the bigger's group-number
            self.groups[p] = self.groups[q]
        else:
            # Merge the smaller group into the bigger's
            self.nums_in_each_group[p] += self.nums_in_each_group[q]
            self.nums_in_each_group[q] = 0
            self.groups[q] = self.groups[p]
        # Numbers of group subtract 1
        self.num_groups -= 1


if __name__ == '__main__':
    UF = UF_Tree_Weighted(5)

    print(f"The initial number of groups is {UF.num_groups}")

    while True:
        p = int(input(f'Input the to-be-merge element: '))
        q = int(input(f"Merge to the target element's group: "))

        if UF.in_the_same_group(p, q):
            print(f"They are already in the same group")
            continue
        UF.unite(p, q)
        print(f"The number of groups now is {UF.count_groups()}")
        print(UF.groups)
        print(f"Elements in each group: {UF.nums_in_each_group}")
运行结果
The initial number of groups is 5
Input the to-be-merge element: 0
Merge to the target element's group: 1
The number of groups now is 4
[1, 1, 2, 3, 4]
Elements in each group: [0, 2, 1, 1, 1]
Input the to-be-merge element: 1
Merge to the target element's group: 2
The number of groups now is 3
[1, 1, 1, 3, 4]
Elements in each group: [0, 3, 0, 1, 1]
Input the to-be-merge element: 3
Merge to the target element's group: 2
The number of groups now is 2
[1, 1, 1, 1, 4]
Elements in each group: [0, 4, 0, 0, 1]
Input the to-be-merge element: 2
Merge to the target element's group: 4
The number of groups now is 1
[1, 1, 1, 1, 1]
Elements in each group: [0, 5, 0, 0, 0]
Input the to-be-merge element: 

当调用unite()合并时,合并时不考虑参数的先后位置,而是考虑分组的大小,总是会有小的分组合并到大的分组

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值