Path Compression and Iteration by Rank in Union Query Sets

1. Path compression

In the ordinary union, we just use a function to find the root node of the node and record it with a variable r and return it, and then directly compare it with another node to see if it is on the same connected component,

 

As shown in the figure, the search efficiency is very low, so if the path is compressed at this time, the depth of the node will be significantly reduced, which will greatly improve the efficiency in the subsequent process of finding the root node, as shown in the following figure:


In this way, the node is directly connected to the root node, which greatly reduces the search efficiency.

Let's first look at the code of the traditional union search:

int find(int x){//Find everyone's final acquaintance (root node)

    int r=x;

    while(r!=parent[r])

        r=parent[r];

    return r;

    }

}

It can be seen that the process of the find function only changes the value of the r variable, but does not change the value of the parent array (which stores the parent node), and if you search like this every time, the time efficiency is really low. Take a look at the code after the path is compressed

int find(int x)//Find the root node

{

    int k, j, r;

    r = x;

    while(r != parent[r]) //find the follower node

        r = parent[r]; //find the root node and record it with r

    k = x;

    while(k != r) //Non-recursive path compression operation

    {

        j = parent[k]; //Use j to temporarily store the parent node of parent[k]

        parent[k] = r; //parent[x] points to the follower node

        k = j; //k moves to the parent node

    }

    return r; //return the value of the root node

}

It can be seen that the value of the parent array (which stores the parent node) is changed during the search. In fact, the root node becomes the parent node during the change process, so that every time you search for the follower node of a point, you don't need to Passing through the parent node again, greatly reducing the number of passing nodes (improving efficiency)

2.  Iterate by rank

The rank here is the depth of the tree. The traditional merge is to merge directly regardless of 3721, without considering the depth of the tree, but we know that the more balanced the tree, the higher the search efficiency, so based on this principle, we merge nodes.

Principle: The rank of the left tree is larger than the rank of the right tree. Let the left one be the root node, as shown in the figure

                                         

The rank of the tree on the left is 3, and the rank of the number on the right is 2, so the combined result is

 

Let's look at the traditional code first:

void cs(int x,int y){//Connect nodes on the same connected component

int p,q;

p=find(x);

q=find(y);

if(p!=q){

    parent[p]=q;

}

Because the rank is required, an array is needed to record the rank of the node (this is also regarded as space for time)

void union_set(int x, int y)//Merge two nodes together

{

    x = find_set(x);

    y = find_set(y);

    if(rank[x] > rank[y])/*Let the higher rank be the parent node*/ parent[y] = x;

    else

    {

        parent[x] = y;

        if(rank[x] == rank[y])

        rank[y]++;//Because two trees of the same height must be connected, there must be a sub-node, so the depth of the tree will be increased by 1 (only the root node needs to be added)

    }

}

Note the initialization of the rank array

for(int i=0;i<=n;i++)

{

    parent[i]=i;

    rank[i]=0;

}

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326501221&siteId=291194637