Print Common Nodes in Two Binary Search Trees

Given two Binary Search Trees, find common nodes in them. In other words, find intersection of two BSTs.

Example:
tree

Method 1 (Simple Solution) A simple way is to one by once search every node of first tree in second tree. Time complexity of this solution is O(m * h) where m is number of nodes in first tree and h is height of second tree.

Method 2:

  • Approach – If we think of another problem in which we are given two sorted arrays and we have to find the intersection between them, we can do it easily using two pointer technique. Now we can easily convert this problem into above. We know that if we store the inorder traversal of a BST in an array, that array will be sorted in ascending order. So what we can do is simply take the inorder traversal of both the trees and store them in two seperate arrays and then find intersection between two arrays.
  • Algorithm –
    1) Do inorder traversal of first tree and store the traversal in an auxiliary array ar1[]. See sortedInorder() here.
    2) Do inorder traversal of second tree and store the traversal in an auxiliary array ar2[]
    3) Find intersection of ar1[] and ar2[]. See this for details.
  • Complexity Analysis:
    • Time Complexity: O(m+n).
      Here ‘m’ and ‘n’ are number of nodes in first and second tree respectively,as we need to traverse both the trees.
    • Auxiliary Space :No use of any data structure for storing values-: O(m+n)
      The reason is that we need two seperate arrays for storing inorder traversals of both the trees.
  • Method 3 (Linear Time and limited Extra Space)
    The idea is to use iterative inorder traversal



  • Approach:
    The idea here is to optimise the space. In the above approach we store all the elements of the tree and then compare but the question is it really necessary to store all the elements. What one can do is store a particular branch of the tree (worst case ‘Height of the tree’) and then start comparing. We can take two stacks and store inorder traversal of trees in respective stacks but the maximum number of elements should be equal to that particular branch of the tree. As soon as that branch ends we start popping and comparing the elements of the stack. Now if top(stack-1)<top(stack-2) there can be more elements in the right branch of top(stack-1) which are greater than it and can be equal to top(stack-2). So we insert right branch of top(stack-1) till it is equal to NULL. At the end of each such insertion we have three conditions to check and then we do the insertions in the stack accordingly.

    if top(stack-1)<top(stack-2)
    root1=root1->right (then do insertions)
    
    if top(stack-1)>top(stack-2)
    root2=root2->right (then do insertions)
    
    else
    It's a match
    
  • C++

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    // C++ program of iterative traversal based method to
    // find common elements in two BSTs.
    #include<iostream>
    #include<stack>
    using namespace std;
      
    // A BST node
    struct Node
    {
        int key;
        struct Node *left, *right;
    };
      
    // A utility function to create a new node
    Node *newNode(int ele)
    {
        Node *temp = new Node;
        temp->key = ele;
        temp->left = temp->right = NULL;
        return temp;
    }
      
    // Function two print common elements in given two trees
    void printCommon(Node *root1, Node *root2)
    {
        // Create two stacks for two inorder traversals
        stack<Node *> stack1, s1, s2;
      
        while (1)
        {
            // push the Nodes of first tree in stack s1
            if (root1)
            {
                s1.push(root1);
                root1 = root1->left;
            }
      
            // push the Nodes of second tree in stack s2
            else if (root2)
            {
                s2.push(root2);
                root2 = root2->left;
            }
      
            // Both root1 and root2 are NULL here
            else if (!s1.empty() && !s2.empty())
            {
                root1 = s1.top();
                root2 = s2.top();
      
                // If current keys in two trees are same
                if (root1->key == root2->key)
                {
                    cout << root1->key << " ";
                    s1.pop();
                    s2.pop();
      
                    // move to the inorder successor
                    root1 = root1->right;
                    root2 = root2->right;
                }
      
                else if (root1->key < root2->key)
                {
                    // If Node of first tree is smaller, than that of
                    // second tree, then its obvious that the inorder
                    // successors of current Node can have same value
                    // as that of the second tree Node. Thus, we pop
                    // from s2
                    s1.pop();
                    root1 = root1->right;
      
                    // root2 is set to NULL, because we need
                    // new Nodes of tree 1
                    root2 = NULL;
                }
                else if (root1->key > root2->key)
                {
                    s2.pop();
                    root2 = root2->right;
                    root1 = NULL;
                }
            }
      
            // Both roots and both stacks are empty
            else  break;
        }
    }
      
    // A utility function to do inorder traversal
    void inorder(struct Node *root)
    {
        if (root)
        {
            inorder(root->left);
            cout<<root->key<<" ";
            inorder(root->right);
        }
    }
      
    /* A utility function to insert a new Node with given key in BST */
    struct Node* insert(struct Node* node, int key)
    {
        /* If the tree is empty, return a new Node */
        if (node == NULL) return newNode(key);
      
        /* Otherwise, recur down the tree */
        if (key < node->key)
            node->left  = insert(node->left, key);
        else if (key > node->key)
            node->right = insert(node->right, key);
      
        /* return the (unchanged) Node pointer */
        return node;
    }
      
    // Driver program
    int main()
    {
        // Create first tree as shown in example
        Node *root1 = NULL;
        root1 = insert(root1, 5);
        root1 = insert(root1, 1);
        root1 = insert(root1, 10);
        root1 = insert(root1,  0);
        root1 = insert(root1,  4);
        root1 = insert(root1,  7);
        root1 = insert(root1,  9);
      
        // Create second tree as shown in example
        Node *root2 = NULL;
        root2 = insert(root2, 10);
        root2 = insert(root2, 7);
        root2 = insert(root2, 20);
        root2 = insert(root2, 4);
        root2 = insert(root2, 9);
      
        cout << "Tree 1 : ";
        inorder(root1);
        cout << endl;
      
        cout << "Tree 2 : ";
        inorder(root2);
      
        cout << "\nCommon Nodes: ";
        printCommon(root1, root2);
      
        return 0;
    }

    chevron_right

    
    

    Java

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    // Java program of iterative traversal based method to 
    // find common elements in two BSTs.
    import java.util.*;
    class GfG { 
      
    // A BST node 
    static class Node 
        int key; 
        Node left, right; 
    }
      
    // A utility function to create a new node 
    static Node newNode(int ele) 
        Node temp = new Node(); 
        temp.key = ele; 
        temp.left = null;
        temp.right = null
        return temp; 
      
    // Function two print common elements in given two trees 
    static void printCommon(Node root1, Node root2) 
          
        Stack<Node> s1 = new Stack<Node> (); 
        Stack<Node> s2 = new Stack<Node> ();
      
        while (true
        
            // push the Nodes of first tree in stack s1 
            if (root1 != null
            
                s1.push(root1); 
                root1 = root1.left; 
            
      
            // push the Nodes of second tree in stack s2 
            else if (root2 != null
            
                s2.push(root2); 
                root2 = root2.left; 
            
      
            // Both root1 and root2 are NULL here 
            else if (!s1.isEmpty() && !s2.isEmpty()) 
            
                root1 = s1.peek(); 
                root2 = s2.peek(); 
      
                // If current keys in two trees are same 
                if (root1.key == root2.key) 
                
                    System.out.print(root1.key + " "); 
                    s1.pop(); 
                    s2.pop(); 
      
                    // move to the inorder successor 
                    root1 = root1.right; 
                    root2 = root2.right; 
                
      
                else if (root1.key < root2.key) 
                
                    // If Node of first tree is smaller, than that of 
                    // second tree, then its obvious that the inorder 
                    // successors of current Node can have same value 
                    // as that of the second tree Node. Thus, we pop 
                    // from s2 
                    s1.pop(); 
                    root1 = root1.right; 
      
                    // root2 is set to NULL, because we need 
                    // new Nodes of tree 1 
                    root2 = null
                
                else if (root1.key > root2.key) 
                
                    s2.pop(); 
                    root2 = root2.right; 
                    root1 = null
                
            
      
            // Both roots and both stacks are empty 
            else break
        
      
    // A utility function to do inorder traversal 
    static void inorder(Node root) 
        if (root != null
        
            inorder(root.left); 
            System.out.print(root.key + " "); 
            inorder(root.right); 
        
      
    /* A utility function to insert a new Node with given key in BST */
    static Node insert(Node node, int key) 
        /* If the tree is empty, return a new Node */
        if (node == null) return newNode(key); 
      
        /* Otherwise, recur down the tree */
        if (key < node.key) 
            node.left = insert(node.left, key); 
        else if (key > node.key) 
            node.right = insert(node.right, key); 
      
        /* return the (unchanged) Node pointer */
        return node; 
      
    // Driver program 
    public static void main(String[] args) 
        // Create first tree as shown in example 
        Node root1 = null
        root1 = insert(root1, 5); 
        root1 = insert(root1, 1); 
        root1 = insert(root1, 10); 
        root1 = insert(root1, 0); 
        root1 = insert(root1, 4); 
        root1 = insert(root1, 7); 
        root1 = insert(root1, 9); 
      
        // Create second tree as shown in example 
        Node root2 = null
        root2 = insert(root2, 10); 
        root2 = insert(root2, 7); 
        root2 = insert(root2, 20); 
        root2 = insert(root2, 4); 
        root2 = insert(root2, 9); 
      
        System.out.print("Tree 1 : " + "\n"); 
        inorder(root1); 
        System.out.println();
        System.out.print("Tree 2 : " + "\n"); 
        inorder(root2); 
        System.out.println();
        System.out.println("Common Nodes: ");
      
        printCommon(root1, root2); 
      
    }

    chevron_right

    
    

    Python3

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    # Python3 program of iterative traversal based 
    # method to find common elements in two BSTs. 
      
    # A utility function to create a new node 
    class newNode:
        def __init__(self, key):
            self.key = key
            self.left = self.right = None
      
    # Function two print common elements 
    # in given two trees 
    def printCommon(root1, root2):
          
        # Create two stacks for two inorder
        # traversals 
        s1 = []
        s2 = []
      
        while 1:
              
            # append the Nodes of first 
            # tree in stack s1 
            if root1:
                s1.append(root1)
                root1 = root1.left
      
            # append the Nodes of second tree
            # in stack s2 
            elif root2:
                s2.append(root2)
                root2 = root2.left
      
            # Both root1 and root2 are NULL here 
            elif len(s1) != 0 and len(s2) != 0:
                root1 = s1[-1
                root2 = s2[-1
      
                # If current keys in two trees are same 
                if root1.key == root2.key:
                    print(root1.key, end = " ")
                    s1.pop(-1
                    s2.pop(-1)
      
                    # move to the inorder successor 
                    root1 = root1.right 
                    root2 = root2.right
      
                elif root1.key < root2.key:
                      
                    # If Node of first tree is smaller, than 
                    # that of second tree, then its obvious 
                    # that the inorder successors of current 
                    # Node can have same value as that of the 
                    # second tree Node. Thus, we pop from s2 
                    s1.pop(-1)
                    root1 = root1.right 
      
                    # root2 is set to NULL, because we need 
                    # new Nodes of tree 1 
                    root2 = None
                elif root1.key > root2.key:
                    s2.pop(-1)
                    root2 = root2.right 
                    root1 = None
      
            # Both roots and both stacks are empty 
            else:
                break
      
    # A utility function to do inorder traversal 
    def inorder(root):
        if root:
            inorder(root.left) 
            print(root.key, end = " ")
            inorder(root.right)
      
    # A utility function to insert a new Node
    # with given key in BST 
    def insert(node, key):
          
        # If the tree is empty, return a new Node 
        if node == None:
            return newNode(key) 
      
        # Otherwise, recur down the tree 
        if key < node.key: 
            node.left = insert(node.left, key) 
        elif key > node.key: 
            node.right = insert(node.right, key)
              
        # return the (unchanged) Node pointer 
        return node
      
    # Driver Code 
    if __name__ == '__main__':
          
        # Create first tree as shown in example 
        root1 = None
        root1 = insert(root1, 5
        root1 = insert(root1, 1
        root1 = insert(root1, 10
        root1 = insert(root1, 0
        root1 = insert(root1, 4
        root1 = insert(root1, 7
        root1 = insert(root1, 9
      
        # Create second tree as shown in example 
        root2 = None
        root2 = insert(root2, 10
        root2 = insert(root2, 7
        root2 = insert(root2, 20
        root2 = insert(root2, 4
        root2 = insert(root2, 9)
      
        print("Tree 1 : "
        inorder(root1) 
        print()
          
        print("Tree 2 : ")
        inorder(root2)
        print()
      
        print("Common Nodes: "
        printCommon(root1, root2)
          
    # This code is contributed by PranchalK

    chevron_right

    
    

    C#

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    using System;
    using System.Collections.Generic;
      
    // C# program of iterative traversal based method to 
    // find common elements in two BSTs. 
    public class GfG
    {
      
    // A BST node 
    public class Node
    {
        public int key;
        public Node left, right;
    }
      
    // A utility function to create a new node 
    public static Node newNode(int ele)
    {
        Node temp = new Node();
        temp.key = ele;
        temp.left = null;
        temp.right = null;
        return temp;
    }
      
    // Function two print common elements in given two trees 
    public static void printCommon(Node root1, Node root2)
    {
        Stack<Node> s1 = new Stack<Node> ();
        Stack<Node> s2 = new Stack<Node> ();
      
        while (true)
        {
            // push the Nodes of first tree in stack s1 
            if (root1 != null)
            {
                s1.Push(root1);
                root1 = root1.left;
            }
      
            // push the Nodes of second tree in stack s2 
            else if (root2 != null)
            {
                s2.Push(root2);
                root2 = root2.left;
            }
      
            // Both root1 and root2 are NULL here 
            else if (s1.Count > 0 && s2.Count > 0)
            {
                root1 = s1.Peek();
                root2 = s2.Peek();
      
                // If current keys in two trees are same 
                if (root1.key == root2.key)
                {
                    Console.Write(root1.key + " ");
                    s1.Pop();
                    s2.Pop();
      
                    // move to the inorder successor 
                    root1 = root1.right;
                    root2 = root2.right;
                }
      
                else if (root1.key < root2.key)
                {
                    // If Node of first tree is smaller, than that of 
                    // second tree, then its obvious that the inorder 
                    // successors of current Node can have same value 
                    // as that of the second tree Node. Thus, we pop 
                    // from s2 
                    s1.Pop();
                    root1 = root1.right;
      
                    // root2 is set to NULL, because we need 
                    // new Nodes of tree 1 
                    root2 = null;
                }
                else if (root1.key > root2.key)
                {
                    s2.Pop();
                    root2 = root2.right;
                    root1 = null;
                }
            }
      
            // Both roots and both stacks are empty 
            else
            {
                break;
            }
        }
    }
      
    // A utility function to do inorder traversal 
    public static void inorder(Node root)
    {
        if (root != null)
        {
            inorder(root.left);
            Console.Write(root.key + " ");
            inorder(root.right);
        }
    }
      
    /* A utility function to insert a new Node with given key in BST */
    public static Node insert(Node node, int key)
    {
        /* If the tree is empty, return a new Node */
        if (node == null)
        {
            return newNode(key);
        }
      
        /* Otherwise, recur down the tree */
        if (key < node.key)
        {
            node.left = insert(node.left, key);
        }
        else if (key > node.key)
        {
            node.right = insert(node.right, key);
        }
      
        /* return the (unchanged) Node pointer */
        return node;
    }
      
    // Driver program 
    public static void Main(string[] args)
    {
        // Create first tree as shown in example 
        Node root1 = null;
        root1 = insert(root1, 5);
        root1 = insert(root1, 1);
        root1 = insert(root1, 10);
        root1 = insert(root1, 0);
        root1 = insert(root1, 4);
        root1 = insert(root1, 7);
        root1 = insert(root1, 9);
      
        // Create second tree as shown in example 
        Node root2 = null;
        root2 = insert(root2, 10);
        root2 = insert(root2, 7);
        root2 = insert(root2, 20);
        root2 = insert(root2, 4);
        root2 = insert(root2, 9);
      
        Console.Write("Tree 1 : " + "\n"); 
        inorder(root1); 
        Console.WriteLine(); 
        Console.Write("Tree 2 : " + "\n"); 
        inorder(root2); 
        Console.WriteLine(); 
        Console.Write("Common Nodes: " + "\n"); 
      
        printCommon(root1, root2);
      
    }
    }
      
    // This code is contributed by Shrikant13

    chevron_right

    
    


    Output:

    4 7 9 10
  • Complexity Analysis:
    • Time Complexity: O(n+m).
      Here ‘m’ and ‘n’ are number of nodes in first and second tree respectively,as we need to traverse both the trees.
    • Auxiliary Space :Use of stack for storing values, at-most elements = ‘Height of tree’: O(h1+h2)
  • This article is contributed by Ekta Goel. Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.

    Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.




    My Personal Notes arrow_drop_up