简体   繁体   中英

lowest common ancestor of n-ary tree

I am trying to find out the lowest common ancestor of binary tree. Here's what's i have tried in C++, but the program stops working(run time error). Can someone suggest me how to improve this?

Also, I know that this program will output the rightmost ancestor of the given nodes, but i am unable to find out a way to find the correct LCA?

#include<cstdio>
#include<iostream>
using namespace std;
#define MARKER ')'
#define N 5
using namespace std;

// A node of N-ary tree
struct Node {
   char key;
   Node *child[N];  // An array of pointers for N children
};


Node *newNode(char key)
{
    Node *temp = new Node;
    temp->key = key;
    for (int i = 0; i < N; i++)
        temp->child[i] = NULL;
    return temp;
}

int height(struct Node *root)
{
    if(root==NULL)
        return 0;
    int hg[N];
    int maxx=-9999;
    for(int i=0;i<N;i++)
    {
        hg[i]=height(root->child[i])+1;
        if(hg[i]>maxx)
        maxx=hg[i];
    }
    return maxx;
}
int size(struct Node*root)
{
    int sz=1;
    if(root==NULL)
    return 0;
   else
   {
    for(int i=0;i<N;i++) sz=sz+size(root->child[i]);
   } 
   return sz;
}

struct Node *LCA(struct Node *a,struct Node *b, struct Node *root)
    {
        cout<<a->key<<" "<<b->key<<endl;
        if(a==root || b==root)
            return root;


        struct Node *temp=NULL;

       for(int i=0;i<N;i++)
        {
            struct Node *res=LCA(a,b,root->child[i]);
            if(res!=NULL)
            {
                temp=res;
            }
        }

        return temp;
}

Node *createDummyTree()
{
    Node *root = newNode('A');
    root->child[0] = newNode('B');
    root->child[1] = newNode('C');
    root->child[2] = newNode('D');
    root->child[0]->child[0] = newNode('E');
    root->child[0]->child[1] = newNode('F');
    root->child[2]->child[0] = newNode('G');
    root->child[2]->child[1] = newNode('H');
    root->child[2]->child[2] = newNode('I');
    root->child[2]->child[3] = newNode('J');
    root->child[0]->child[1]->child[0] = newNode('K');
    return root;
}


void traverse(Node *root)
{
    if (root)
    {
        printf("%c ", root->key);
        for (int i = 0; i < N; i++)
            traverse(root->child[i]);
    }
}

int main()
{
        Node *root = createDummyTree();
        cout<<height(root)<<endl;
        cout<<size(root)<<endl;
        cout<<LCA(root->child[2]->child[0],root->child[2]->child[1],root)->key<<endl;


    return 0;
}

The solution is very simple my Friend. First we include a parent pointer and level field for every node.

struct Node {
   char key;
   Node *child[N];
   Node *parent;
   int level; // An array of pointers for N children
};

Now we will take advantage of the above structure.

The main point is to first bring the two pointers at the same level, If by doing so, they become equal, then we are done,if they don't we simply move 1 level above for the both pointers till they become equal. Thats it.

One more important point, you do not need to pass the root pointer to LCA, So your main function is like this:

int main()
{
        Node *root = createDummyTree();
        cout<<LCA(root->child[2]->child[0],root->child[2]->child[1])->key<<endl;
    return 0;
}

your LCA function will be like this.

struct Node *LCA(struct Node *a,struct Node *b)
    {
      struct Node *larger,*smaller;
      if(a->level>b->level)
        {larger=a;smaller=b;}
      else {larger=b;smaller=a;}    
      while(larger->level!=smaller->level)
         larger=larger->parent;    
      while(larger!=smaller)
      {
          larger=larger->parent;
          smaller=smaller->parent;
      }
      return larger;//you can also return smaller here.
    }

and in your createDummyTree, only additional thing you have to do is set the parent and level of every node and it will be like this.

Node *createDummyTree()
{
    Node *root = newNode('A');
    root->level=0;
    root->child[0] = newNode('B');
    root->child[0]->parent=root;
    root->child[0] ->level=1;
    root->child[1] = newNode('C');
    root->child[1]->parent=root;
    root->child[1] ->level=1;
    root->child[2] = newNode('D');
    root->child[2]->parent=root;
    root->child[2] ->level=1;
    root->child[0]->child[0] = newNode('E');
    root->child[0]->child[0]->parent=root->child[0];
    root->child[0]->child[0]->level=2;
    root->child[0]->child[1] = newNode('F');
    root->child[0]->child[1]->parent=root->child[0];
    root->child[0]->child[1]->level=2;
    root->child[2]->child[0] = newNode('G');
    root->child[2]->child[0]->parent=root->child[2];
    root->child[2]->child[0]->level=2;
    root->child[2]->child[1] = newNode('H');
    root->child[2]->child[1]->parent=root->child[2];
    root->child[2]->child[1]->level=2;
    root->child[2]->child[2] = newNode('I');
    root->child[2]->child[2]->parent=root->child[2];
    root->child[2]->child[2]->level=2;
    root->child[2]->child[3] = newNode('J');
    root->child[2]->child[3]->parent=root->child[2];
    root->child[2]->child[3]->level=2;
    root->child[0]->child[1]->child[0] = newNode('K');
    root->child[0]->child[1]->child[0]->parent=root->child[0]->child[1];
    root->child[0]->child[1]->child[0]->level=3;
    return root;
}

The above code will give you the answer in O(height) even in worst case.

If you are looking for lca in a n-ary tree that has only downward pointers, you would like to search down the tree for the lowest node that holds that both a and b are reachable from Try thinking about this angle

I would suggest creating a method that finds if a is descendant of b. Then I would create a method that receives a node, ancestor, and two other nodes, a and b, and says: are a and b reachable from ancestor? Then I would have a function that does the following: for each son, are a and b reachable from my son, return the result of this recursive function called with that son. If no son holds this requirement I will return the father if a and b are reachable from him. Then I would call the third method with root as the father, and with a and b. Hope this helps

I found many different approaches to address this problem, such as:

  1. Keeping track of parent of each node in Node struct ( link )
  2. Using Euler tour while mapping the original nodes to Euler numbers ( link ) or keeping track of depth of each node (link )
  3. But the following small code is the easiest one in my point of view:

Assumption:

  • it assumes both of the given nodes exist in the given n-ary tree. To fix it we can run another method to verify first if they both exist in the tree.

How does it work:

  1. There are two option we need to consider to find the Lowest Common ancestor for a given node

  2. Option1: Both of the given nodes are in same sub-tree and one of them is lowest common ancestor, this is the case the given algorithm return temp

  3. Option2: One of the given nodes belong one sub-tree of the visiting node and the other one belongs to the other one, in this case we need to return the visiting node which is implemented in this algorithm under the condition checking of (if count==2 )

     Node LCA(Node a, Node b, Node root) { if(a == root || b == root) return root; int count = 0; Node temp = null; for(Node iter : root.children) { Node res = LCA(a, b, iter); if(res != null) { count++; temp = res; } } if(count == 2) return root; return temp;

    }

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