Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the Time Complexity of Quick Union?

I'm taking the coursera course on Data Structures and Algorithms. The author mentions that Quick Find is O(N^2) which makes sense (given that N union operations on N objects might require N*N array accesses). However, I don't understand why Quick Union would be any better. It seems that in the worst case, one long narrow tree, N Find operations on N objects would also lead to O(N^2) yet the material says it's O(N).

So, one is quadratic time, and one is linear. I'm not sure that I understand why there is a difference. Example:

Quick find approach

int[] id = new int[10];

for(int i = 0; i < 10; i++)
    id[i] = i;  

// Quick find approach

int QuickFind(int p)
{
    return id[p];
}

public void Union(int p, int q)
{
    int pId = find(p);
    int qId = find(q);

    if (pId == qId)
        return;

    for (int i = 0; i < id.length; i++)
    {
        if(id[i] == pId)
            id[i] = qId;
    }
}

Quick union approach

int Find(int p)
{
    while(p != id[p])
        p = id[p];

    return p;
}

void QuickUnion(int p, int q)
{
    int pRoot = Find(p);
    int qRoot = Find(q);

    if(pRoot == qRoot)
        return;

    id[pRoot] = qRoot;
}
like image 250
user3457614 Avatar asked Mar 27 '17 00:03

user3457614


1 Answers

// Naive implementation of find
int find(int parent[], int i)
{
    if (parent[i] == -1)
        return i;
    return find(parent, parent[i]);
}

// Naive implementation of union()
void Union(int parent[], int x, int y)
{
    int xset = find(parent, x);
    int yset = find(parent, y);
    parent[xset] = yset;
}

The above union() and find() are naive and the worst case time complexity is linear. The trees created to represent subsets can be skewed and can become like a linked list. Following is an example worst case scenario.

Let there be 4 elements 0, 1, 2, 3

Initially all elements are single element subsets.
0 1 2 3 

Do Union(0, 1)
   1   2   3  
  /
 0

Do Union(1, 2)
     2   3   
    /
   1
 /
0

Do Union(2, 3)
         3    
        /
      2
     /
   1
 /
0

The above operations can be optimized to O(Log n) in worst case. The idea is to always attach smaller depth tree under the root of the deeper tree. This technique is called union by rank. The term rank is preferred instead of height because if path compression technique (I've discussed it below) is used, then rank is not always equal to height.

Let us see the above example with union by rank
Initially all elements are single element subsets.
0 1 2 3 

Do Union(0, 1)
   1   2   3  
  /
 0

Do Union(1, 2)
   1    3
 /  \
0    2

Do Union(2, 3)
    1    
 /  |  \
0   2   3

The second optimization to naive method is Path Compression. The idea is to flatten the tree when find() is called. When find() is called for an element x, root of the tree is returned. The find() operation traverses up from x to find root. The idea of path compression is to make the found root as parent of x so that we don’t have to traverse all intermediate nodes again. If x is root of a subtree, then path (to root) from all nodes under x also compresses.

Let the subset {0, 1, .. 9} be represented as below and find() is called
for element 3.
              9
         /    |    \  
        4     5      6
     /     \        /  \
    0        3     7    8
            /  \
           1    2  

When find() is called for 3, we traverse up and find 9 as representative
of this subset. With path compression, we also make 3 as child of 9 so 
that when find() is called next time for 1, 2 or 3, the path to root is 
reduced.

               9
         /    /  \    \
        4    5    6     3 
     /           /  \   /  \
    0           7    8  1   2           

The two techniques complement each other. The time complexity of each operations becomes even smaller than O(logn) ~ O(n). In fact, amortized time complexity effectively becomes small constant.

I didn't post the code with above optimization because it's the assignment part I guess. Hope it helps!

like image 197
Kaidul Avatar answered Oct 12 '22 14:10

Kaidul