Weighted Quick-Union with Path Compression algorithm

主宰稳场 提交于 2019-12-03 01:13:49
Andrew Tomazos

First understand that id is a forest. id[i] is the parent of i. If id[i] == i it means that i is a root.

For some root i (where id[i] == i) then iz[i] is the number of elements in the tree rooted at i.

public int root(int i)
{
    while(i != id[i])
    {
        id[i] = id[id[i]];   // this line represents "path compression"
        i = id[i];
    }
    return i;
}

How does the path compression work? id[i] = id[id[i]] means that we reach only the second ancester of our node, not the root.

As we are ascending the tree to find the root we move nodes from their parents to their grandparents. This partially flattens the tree. Notice that this operation doesn't change which tree the node is a member of, this is all we are interested in. This is the path compression technique.

(You did notice the loop right? while(i == id[i]) terminates once i is a root node)

iz[] contains integers from 0 to N-1. How does iz[] help us know the number of elements in the set?

There is a transcription error in the code:

for(int i = 0; i < id.length; i++)
{
    iz[i] = i; // WRONG
    id[i] = i;
}

This is the correct version:

for(int i = 0; i < id.length; i++)
{
    iz[i] = 1; // RIGHT
    id[i] = i;
}

iz[i] is the number of elements for a tree rooted at i (or if i is not a root then iz[i] is undefined). So it should be initialized to 1, not i. Initially each element is a seperate "singleton" tree of size 1.

id[i] = id[id[i]]; // this line represents "path compression"

The above code is "Simpler one-pass variant" as mentioned in the slide of Union Find (Algorithms, Part I by Kevin Wayne and Robert Sedgewick). Therefore your guess for question 1 is correct. Each examined node points to its grandparent.

To make each examined node points to the root we will need two-pass implementation:

  /**
 * Returns the component identifier for the component containing site <tt>p</tt>.
 * @param p the integer representing one site
 * @return the component identifier for the component containing site <tt>p</tt>
 * @throws java.lang.IndexOutOfBoundsException unless 0 <= p < N
 */
public int find(int p) {
    int root = p;
    while (root != id[root])
        root = id[root];
    while (p != root) {
        int newp = id[p];
        id[p] = root;
        p = newp;
    }
    return root;
}

Reference: http://algs4.cs.princeton.edu/15uf/WeightedQuickUnionPathCompressionUF.java.html

Question 1. It is not right to say that the line id[i] = id[id[i]]; only reaches the second ancestor of the root.You will realize that while loop while(i != id[i]) stops only when the node i is pointing at the root i.e when i == id[i].By this time we shall have pointed the node to the root using the line id[i] = id[id[i]]; where the inner id[i] is the root.

Question 2.

You are wrong to initialize iz[i] = i; actually it should be iz[i] = 1; meaning, each and every node size is initialized by 1 at the beginning since they are of size 1. In the union function you realize that we have the lines iz[j] += iz[i]; and iz[i] += iz[j]; which updates the size of the root node to be the sum of the sizes of the two components joined together. This efficiently updates the nodes sizes.

Gaurav jhamnani

One more thing to be noted here:

While finding the root when we are making id[i]=id[id[i]] i.e; making i under its grand parent

-then size of id[i] will decrease by size of i i,e; iz[id[i]]-=iz[i]

Now this makes code perfectly correct.

I am not sure about this but intuitively i feel, Its absence does not cause problems because we are always comparing size of the roots.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!