QuickUnion

QuickUnion

  QuickUnion的原理较简单,每次连接两元素时找到两元素对应根节点,连接根节点即可。

class QuickUnion(object):
    def __init__(self, n):
        self.__parent = list(range(n))

    def get_root(self, p):
        p_parent = self.__parent[p]
        while p_parent != self.__parent[p_parent]:
            p_parent = self.__parent[p_parent]
        return p_parent

    def connect(self, a, b):
        self.__parent[self.get_root(a)] = self.__parent[self.get_root(b)]

    def is_connected(self, a, b):
        return self.get_root(a) == self.get_root(b)

  若树极不平衡,如1(root) -> 2 -> 3 -> 4 -> 5,则效率与链表相同。对于含有 N N N个元素的并查集,时间复杂度为 Θ ( N ) \Theta(N) Θ(N)。为避免这种情况出现,引入WeigtedQuickUnion。

WeigtedQuickUnion

  WeigtedQuickUnion原理与QuickUnion相同,但会额外记录每棵树的大小。实际上,并查集的的效率取决于高度最大的树的高度。因此,每次连接时将较小的树(所含元素较少)连接到较大的树上。遵循此规则(注意:所有的树都是满足在此规则下生成的),在最坏的情况下,对于含有 N N N个元素的并查集,最大高度为 Θ ( log ⁡ N ) \Theta(\log N) Θ(logN),因此时间复杂度为 Θ ( log ⁡ N ) \Theta(\log N) Θ(logN)

class WeightedQuickUnionDS:
    def __init__(self, n):
        self.__parent = list(range(n))
        self.__size = [1 for _ in range(n)]

    def get_root(self, p):
        p_parent = self.__parent[p]
        while p_parent != self.__parent[p_parent]:
            p_parent = self.__parent[p_parent]
        return p_parent

    def connect(self, a, b):
        a_root = self.get_root(a)
        b_root = self.get_root(b)
        if self.__size[a_root] > self.__size[b_root]:
            self.__parent[b_root] = self.__parent[a_root]
            self.__size[a_root] += self.__size[b_root]
        else:
            self.__parent[a_root] = self.__parent[b_root]
            self.__size[b_root] += self.__size[a_root]

    def is_connected(self, a, b):
        return self.__parent[self.get_root(a)] == self.__parent[self.get_root(b)]

  注意到每次查询时都需从头寻找一次根节点,可以进一步改进。

WeigtedQuickUnion With Path Compression

  更进一步,在每次查询时将查询路径上所有点点直接连接到根节点上,以后查询时就不需再从头查找。

class WQUPCDS(object):
    def __init__(self, n):
        self.__parent = list(range(n))
        self.__size = [1 for _ in range(n)]

    def get_root(self, a):
        a_parent = self.__parent[a]
        while a_parent != self.__parent[a_parent]:
            a_parent = self.__parent[a_parent]
        return a_parent

    def connect(self, a, b):
        a_root = self.get_root(a)
        b_root = self.get_root(b)
        if self.__size[a_root] > self.__size[b_root]:
            self.__parent[b_root] = self.__parent[a_root]
            self.__size[a_root] += self.__size[b_root]
        else:
            self.__parent[a_root] = self.__parent[b_root]
            self.__size[b_root] += self.__size[a_root]

    def is_connected(self, a, b):
        a_root = self.get_root(a)
        b_root = self.get_root(b)
        a_id = a
        b_id = b
        while a_id != self.__parent[a_id]:
            parent = self.__parent[a_id]
            self.__parent[a_id] = a_root
            a_id = parent
        while b_id != self.__parent[b_id]:
            parent = self.__parent[b_id]
            self.__parent[b_id] = b_root
            b_id = parent
        return a_root == b_root

  该算法的时间复杂度为 lg ⁡ ∗ N \lg^*{N} lgN

N N N lg ⁡ ∗ N \lg^*{N} lgN
10
21
42
163
2 16 2^{16} 2164
2 256 2^{256} 22565
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值