微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

教科书Union-Find算法的实现不起作用

如何解决教科书Union-Find算法的实现不起作用

我有两种 union-find 的实现:一种是我自己提出的(它有效),另一种是基于教科书的解释(令人惊讶的是,它不起作用)。当我在输入此代码时调试有问题的实现时,也许有人能够指出一个到目前为止我无法理解的错误

我一直在使用以下内容

https://www.cl.cam.ac.uk/teaching/1415/Algorithms/disjointsets.pdf

可以在以下位置找到更多信息:

https://en.wikipedia.org/wiki/Disjoint-set_data_structure

https://cp-algorithms.com/data_structures/disjoint_set_union.html

实现代码

from collections import Counter

def edges2vertices(edges):
    return sorted(list({vertex for edge in edges for vertex in edge}))

class UnionFindTextbook:
    def __init__(self,vertices):
        self._parents = {vertex: vertex for vertex in vertices}

    def find(self,s):
        if s == self._parents[s]:
            return s
        self._parents[s] = self.find(self._parents[s])
        return self._parents[s]

    def union(self,a,b):
        a = self.find(a)
        b = self.find(b)
        if a != b:
            self._parents[b] = a

    @property
    def partitions(self):
        return Counter(self._parents.values()).values()

class UnionFindOwn:
    def __init__(self,vertices):
        self._lookup = {v: idx for idx,v in enumerate(vertices)}
        self._forest = [[vertex] for vertex in vertices]

    def union(self,b):
        a = self.find(a)
        b = self.find(b)
        if self._should_merge(a,b) and self._can_merge(a,b):
            self._forest[a].extend(self._forest[b])
            for i in self._forest[b]:
                self._lookup[i] = a
            self._forest[b] = []

    def find(self,a):
        return self._lookup[a]

    def _should_merge(self,b):
        return a != b

    def _can_merge(self,b):
        return self._forest[a] and self._forest[b]

    @property
    def partitions(self):
        return [len(tree) for tree in self._forest if tree]

def unionfind_min_max(edges,strategy):
    vertices = edges2vertices(edges)
    uf = strategy(vertices)
    for a,b in edges:
        uf.union(a,b)
    return min(uf.partitions),max(uf.partitions)

测试代码

import unittest
from typing import List,Tuple

import ddt

from unionfind import unionfind_min_max,UnionFindOwn as STRATEGY

DATA_UNIONFIND_MIN_MAX = [
    {  # 1.
       # 5
       # 3-8
       # 4-9
       # 1-6-2-7
        "edges": [
            (1,6),(2,7),(3,8),(4,9),],"strategy": STRATEGY,"expected": (2,4),},]

@ddt.ddt
class TestUnionFind(unittest.TestCase):
    @ddt.unpack
    @ddt.data(*DATA_UNIONFIND_MIN_MAX)
    def test_unionfind_min_max(self,edges: List[Tuple[int]],strategy,expected: Tuple[int]) -> None:
        actual = unionfind_min_max(edges,strategy)
        self.assertEqual(expected,actual)

有人可以指出 UnionFindTextbook 中的错误吗?

最小可重现示例:

from collections import Counter

def edges2vertices(edges):
    return sorted(list({vertex for edge in edges for vertex in edge}))

class UnionFindTextbook:
    def __init__(self,b):
        a = self.find(a)
        b = self.find(b)
        if a != b:
            self._parents[b] = a

    @property
    def partitions(self):
        return Counter(self._parents.values()).values()

def unionfind_min_max(edges,strategy=UnionFindTextbook):
    vertices = edges2vertices(edges)
    uf = strategy(vertices)
    for a,max(uf.partitions)

edges = [
    (1,]

assert unionfind_min_max(edges) == (2,4)

解决方法

我已经设法适当地修改了代码,但我不确定为什么所有的消息来源都没有提到在 union() 操作之后数据结构不会处于所需的状态。

@property
def partitions(self):
    return Counter(self.find(i) for i in self._parents).values()

有什么想法吗?

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。