Problem: find the common ancestor of two nodes in a tree
Given a "tree" pointer pointing to the root node of a tree and the other two pointers to two nodes in the tree. You are expected to write a C++ subroutine to find the common ancestor of the two nodes. In any unexpected condition, your code should return null pointer and avoid crashing.
For example, if the tree is like below, B is the common ancestor of E and G; A is the common ancestor of H and F; D is the common ancestor of D and G.
You are allowed to use recursion but as few as possible. You are NOT allowed to use STL. Please follow the type definitions shown below:
// tree node typetypedef struct _Node ...{ char value; struct _Node* left; struct _Node* right; }Node; class CommonNodeFinder ...{ //add any auxiliary code here as you wish. public: inline Node* FindCommonAncestor(Node* tree, Node* node_1, Node* node_2) ...{ //your code here. } }
my solution:
#include <iostream>
template< typename T >
class stack{
public:
struct Node{
T value;
Node* next;
};
public:
stack()
{
phead = NULL;
}
virtual ~stack()
{
Node* pnode = phead;
while ( pnode != NULL )
{
phead = phead->next;
delete pnode;
pnode = phead;
}
}
void push_back( T value )
{
Node* ptempnode = new Node;
ptempnode->value = value;
ptempnode->next = phead;
phead = ptempnode;
}
T get( ) const
{
return phead->value;
}
void pop_up( )
{
Node* pnode;
pnode = phead;
phead = phead->next;
delete pnode;
}
bool is_empty( ) const
{
if ( phead == NULL )
return true;
else
return false;
}
private:
Node* phead;
};
template < typename T >
struct Node
{
T value;
Node* left;
Node* right;
};
void visit( Node<char>* p )
{
std::cout << p->value << std::endl;
}
class CommonNodeFinder
{
public:
// auxiliary function used for generating tree
void generate_tree( char tree_serial[] )
{
int n = strlen( tree_serial );
if ( n < 1 )
{
tree_phead = NULL;
return;
}
Node<char>* node;
node = new Node<char>;
node->value = tree_serial[0];
node->left = generate_child( tree_serial, 1, n );
node->right = generate_child( tree_serial, 2, n );
tree_phead = node;
return;
}
// auxiliary function used for generating tree
Node<char>* generate_child( char tree_serial[], const int& index, const int& length )
{
if ( index >= length || tree_serial[index] == ' ' )
return NULL;
Node<char>* node;
node = new Node<char>;
node->value = tree_serial[index];
node->left = generate_child( tree_serial, 2 * index + 1 , length );
node->right = generate_child( tree_serial, 2 * index + 2, length );
return node;
}
// auxiliary function used for visit the tree
void pre_order_traverse( Node<char>* pnode, void ( *visit ) ( Node<char>* p ))
{
if( pnode != NULL )
{
visit( pnode );
pre_order_traverse( pnode->left, visit );
pre_order_traverse( pnode->right, visit );
}
}
// auxiliary function used for delete the tree
void delete_tree( Node<char>* pnode )
{
if ( pnode != NULL )
{
delete_tree( pnode->left );
delete_tree( pnode->right );
delete pnode;
}
}
// get the Node by the value
Node<char>* find_in( char val, Node<char>* root )
{
Node<char>* node;
if( root == NULL )
return NULL;
else if ( root->value == val )
return root;
else if ( ( node = find_in( val, root->left ) ) != NULL )
return node;
else if ( ( node = find_in( val, root->right ) ) != NULL )
return node;
else
return NULL;
}
//generator the ancestor stack for node in the root
bool is_belong_to( Node<char>* node, Node<char>* root, stack< Node<char>* >& ancestors )
{
if ( root == NULL )
return false;
else if ( node == root )
{
ancestors.push_back( root );
return true;
}
else if ( is_belong_to( node, root->left, ancestors ) )
{
ancestors.push_back( root );
return true;
}
else if ( is_belong_to( node, root->right, ancestors ) )
{
ancestors.push_back( root );
return true;
}
else
return false;
}
public:
Node<char>* tree_phead;
CommonNodeFinder( )
{
tree_phead = NULL;
}
virtual ~CommonNodeFinder( )
{
delete_tree( tree_phead );
}
public:
inline Node<char>* FindCommonAncestor(Node<char>* tree, Node<char>* node_1, Node<char>* node_2)
{
stack< Node<char>* > ancestor1;
stack< Node<char>* > ancestor2;
is_belong_to( node_1, tree, ancestor1 );
is_belong_to( node_2, tree, ancestor2 );
if ( ancestor1.is_empty() )
return NULL;
if ( ancestor2.is_empty() )
return NULL;
Node<char> *a1, *a2, *a;
a1 = ancestor1.get();
a2 = ancestor2.get();
while ( a1 == a2 )
{
a = a1;
ancestor1.pop_up();
if ( ancestor1.is_empty() )
break;
ancestor2.pop_up();
if ( ancestor2.is_empty() )
break;
a1 = ancestor1.get();
a2 = ancestor2.get();
}
return a;
}
};
// test code
int main ( int argc, char* argv[] )
{
CommonNodeFinder NodeFinder;
Node<char>* node1;
Node<char>* node2;
Node<char>* node;
NodeFinder.generate_tree( "ABCDE HFG" );
node1 = NodeFinder.find_in( 'D', NodeFinder.tree_phead );
node2 = NodeFinder.find_in( 'G', NodeFinder.tree_phead );
node = NodeFinder.FindCommonAncestor( node1, NodeFinder.tree_phead, node2 );
if ( node )
std::cout << node->value << std::endl;
}