为不相交集实现Find()方法时出现问题

时间:2018-12-13 07:33:18

标签: java disjoint-sets

暂时尝试解决此问题。我得到了一个不相交集合中的节点。该节点的实现是一个类,在该类中它具有​​不同的父节点或者是它自己的

class Node {
    Node parent;
    int rank;
    //...constructor and method declarations}

现在,我必须使用路径压缩为该类实现Find方法,称为getParent()方法。我写了以下代码:

Node getParent(){
    while(parent != this)
    {
        parent = parent.getParent();  
    }
    return parent;

我得到了这个代码的无限递归。我知道这是有问题的,但我不知道如何解决。我尝试使用this关键字,但导致了相同的错误。 请帮忙。此外,对于如何以迭代方式编写此代码的见解也将是一个不错的选择。 另外,我想重新构造树,以便在调用getParent()的节点与根之间的所有中间节点都具有一个公共父节点,即根节点。

2 个答案:

答案 0 :(得分:0)

Node getParent() {
    while (parent != this) {
        parent = parent.getParent();  
    }
    return parent;
}

问题:

  1. 您正在更改parent字段。
  2. 您应该测试父母的父母本身是否...不是这个。

您的代码应该是:

Node getParent() {
    Node p = parent;
    while(p.parent != p) {
        p = p.parent;  
    }
    return p;
}

或递归:

Node getParent() {
    return (parent == this) ? this : parent.getParent();
}

(在这种情况下,迭代版本更安全。您不应获得“无限”的递归,但仍然存在可能会使用病理上较深的数据结构来递归得太深的风险。)


更新-显然,您打算让getParent(逐渐)折叠其访问的每个Node的父链。在这种情况下,递归解决方案将是:

Node getParentAndCollapse() {
    if (parent == this) {
        return this;
    } else {
        parent = parent.getParentAndCollapse();
        return parent;
    }
}

要折叠整个链的迭代解决方案,需要对链进行两次遍历:

  1. 遍历链条找到最终的父母。
  2. 再次遍历链,更新所有parent字段以引用最终的父级。
  3. 归还最终父母。

类似这样的东西

Node getParentAndCollapse() {
    Node p = getParent();  // iterative version
    Node n = this;
    while (n.parent != p) {
        Node np = n.parent;
        n.parent = p;
        n = np;
    }
    return p;
}

答案 1 :(得分:0)

斯蒂芬已经回答了问题的第一部分,我认为这已经足够完整了。

关于问题的第二部分,我假设您将所有节点都放在列表中。因此,您拥有List<Node> allNodes。重构树的所需方法是:

public void reStructureTree(List<Node> allNodes){
    for(Node item: allNodes){
        Node p = item.parent;
        List<Node> branch = new ArrayList<>();

        while (p.parent != p){
            branch.add(p);
            p = p.parent;
        }

        for(Node branchItem : branch){
            branchItem.parent = p;
        }
    }
}

在最坏的情况下,此方法的顺序为O(n^2),并且我没有寻找更好的方法,因为您没有提到它的重要性。