Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lowest Common Ancestor Algorithm

So I have been looking into implementing a lowest common ancestor algorithm. I looked at many different algorithms (mainly variations of Trajan's solution or variations of the RMQ).

I am using a non-binary tree. My tree will often change between queries and therefore pre-processing wouldn't necessarily be worthwhile. The tree shouldn't have more than 50-75 nodes. What I am wondering is whether I should bother using their algorithms or just stick with my own.

My Algorithm

myLCA(node1, node2) {
    parentNode := [ ]
    while (node1!=NULL) {
         parentNode.push(node1)
         node1 := node1.parent
    }
     while (node2!=NULL) {
         for i in parentNode.size {
             if (parentNode(i) == node2) {
                 return node2; 
             }
         }
         node2 := node2.parent
     }

}       
like image 662
slimbo Avatar asked Jun 14 '11 02:06

slimbo


People also ask

What is meant by lowest common ancestor?

The lowest common ancestor is the lowest node in the tree that has both n1 and n2 as descendants, where n1 and n2 are the nodes for which we wish to find the LCA. Hence, the LCA of a binary tree with nodes n1 and n2 is the shared ancestor of n1 and n2 that is located farthest from the root.

What is LCA in competitive programming?

Lowest Common Ancestor - Binary Lifting - Algorithms for Competitive Programming.

How do you find the lowest common ancestor in C?

First we need to look for node_1 and node_2 in given tree. If they lie on different sides of root node, then the root itself will be the LCA of node_1 and node_2. 2. If root is greater than node_1 and node_2 then their LCA will lie on left subtree.

What is LCA in binary tree?

What is “Lowest Common Ancestor (LCA)”? It is the lowest level parent shared by two nodes within a tree. Let's take a look at an example: Image by Author. Within the above binary tree, nodes 8 and 10 are highlighted.


1 Answers

As others have mentioned, your algorithm is currently quadratic. That may not be a problem for a dataset as small as 50-75 nodes, but in any case it's straightforward to change it to linear time without using any sets or hashtables, just by recording the complete path to the root for each node, then walking back down from the root and looking for the first different node. The immediately preceding node (which is the common parent of these 2 different nodes) is then the LCA:

linearLCA(node1, node2) {
    parentNode1 := [ ]
    while (node1!=NULL) {
         parentNode1.push(node1)
         node1 := node1.parent
    }
    parentNode2 := [ ]
    while (node2!=NULL) {
         parentNode2.push(node2)
         node2 := node2.parent
    }
    while (node1 == node2 && !isEmpty(parentNode1) && !isEmpty(parentNode2)) {
        oldNode := node1
        node1 := parentNode1.pop()
        node2 := parentNode2.pop()
    }
    if (node1 == node2) return node1    // One node is descended from the other
    else return oldNode                 // Neither is descended from the other
}

EDIT 27/5/2012: Handle the case in which one node is descended from the other, which would otherwise result in attempting to pop() an empty stack. Thanks to damned for pointing this out. (I also realised that it's sufficient to track a single oldNode.)

like image 103
j_random_hacker Avatar answered Sep 28 '22 08:09

j_random_hacker