简体   繁体   中英

Problem while implementing Find() method for a disjoint set

Been trying to solve this for a while now. I've been given a Node in a Disjoint Set.The Node's implementation is as a class where either it has a different parent node or is it's own

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

Now, I have to implement the Find method for this class with path compression, called the getParent() method. I wrote the following code:

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

I get infinite recursion with this code. I know it's problematic, but I do not know how to fix it. I tried using the this keyword, but it led to the same errors. Please help. Also, an insight on how to write this code in an iterative manner would be a great plus. Also, I would like to restructure the tree such that all intermediate nodes between the node on which the getParent() is called and the root have a common parent ie the root node.

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

The problems:

  1. You are mutating the parent field.
  2. You should be testing if the parent's parent is itself ... not this.

Your code should probably be:

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

Or recursively:

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

(In this case, the iterative version is safer. You should not get "infinite" recursion, but there is still a risk that you may recurse too deep, with a pathologically deep data structure.)


UPDATE - apparently, it is your intention that getParent should (incrementally) collapse the parent chain of each Node it visit. In that case, the recursive solution would be:

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

An iterative solution that collapses the entire chain requires two traversals of the chain:

  1. Traverse the chain find the ultimate parent.
  2. Traverse the chain again, updating all the parent fields to refer to the ultimate parent.
  3. Return the ultimate parent.

Something like this

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;
}

The first part of your question is already answered by Stephen, and I think this is complete enough.

About the second part of your question, I assume you have all the nodes in a list. So you have List<Node> allNodes . The needed method to restructure the tree would be:

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;
        }
    }
}

The order of this method in the worst case would be O(n^2) and I did not look for a better way, cause you didn't mention the importance of it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM