Given two Binary Search Trees(BST), print the elements of both BSTs in sorted form. The expected time complexity is O(m+n) where m is the number of nodes in the first tree and n is the number of nodes in the second tree. The maximum allowed auxiliary space is O(height of the first tree + height of the second tree).
Examples:
First BST
3
/ \
1 5
Second BST
4
/ \
2 6
Output: 1 2 3 4 5 6
First BST
8
/ \
2 10
/
1
Second BST
5
/
3
/
0
Output: 0 1 2 3 5 8 10
Source: Google interview question
A similar question has been discussed earlier. Let us first discuss the already discussed methods of the previous post which was for Balanced BSTs. Method 1 can be applied here also, but the time complexity will be O(n^2) in the worst case. Method 2 can also be applied here, but the extra space required will be O(n) which violates the constraint given in this question. Method 3 can be applied here but step 3 of method 3 can’t be done in O(n) for an unbalanced BST.
Thanks to Kumar for suggesting the following solution.
The idea is to use iterative inorder traversal. We use two auxiliary stacks for two BSTs. Since we need to print the elements in the sorted form, whenever we get a smaller element from any of the trees, we print it. If the element is greater, then we push it back to stack for the next iteration.
C++
#include <bits/stdc++.h>using namespace std;// Structure of a BST Node class node { public: int data; node *left; node *right; }; //.................... START OF STACK RELATED STUFF.................... // A stack node class snode { public: node *t; snode *next; }; // Function to add an elemt k to stack void push(snode **s, node *k) { snode *tmp = new snode(); //perform memory check here tmp->t = k; tmp->next = *s; (*s) = tmp; } // Function to pop an element t from stack node *pop(snode **s) { node *t; snode *st; st=*s; (*s) = (*s)->next; t = st->t; free(st); return t; } // Fucntion to check whether the stack is empty or not int isEmpty(snode *s) { if (s == NULL ) return 1; return 0; } //.................... END OF STACK RELATED STUFF.................... /* Utility function to create a new Binary Tree node */node* newNode (int data) { node *temp = new node; temp->data = data; temp->left = NULL; temp->right = NULL; return temp; } /* A utility function to print Inoder traversal of a Binary Tree */void inorder(node *root) { if (root != NULL) { inorder(root->left); cout<<root->data<<" "; inorder(root->right); } } // The function to print data of two BSTs in sorted order void merge(node *root1, node *root2) { // s1 is stack to hold nodes of first BST snode *s1 = NULL; // Current node of first BST node *current1 = root1; // s2 is stack to hold nodes of second BST snode *s2 = NULL; // Current node of second BST node *current2 = root2; // If first BST is empty, then output is inorder // traversal of second BST if (root1 == NULL) { inorder(root2); return; } // If second BST is empty, then output is inorder // traversal of first BST if (root2 == NULL) { inorder(root1); return ; } // Run the loop while there are nodes not yet printed. // The nodes may be in stack(explored, but not printed) // or may be not yet explored while (current1 != NULL || !isEmpty(s1) || current2 != NULL || !isEmpty(s2)) { // Following steps follow iterative Inorder Traversal if (current1 != NULL || current2 != NULL ) { // Reach the leftmost node of both BSTs and push ancestors of // leftmost nodes to stack s1 and s2 respectively if (current1 != NULL) { push(&s1;, current1); current1 = current1->left; } if (current2 != NULL) { push(&s2;, current2); current2 = current2->left; } } else { // If we reach a NULL node and either of the stacks is empty, // then one tree is exhausted, ptint the other tree if (isEmpty(s1)) { while (!isEmpty(s2)) { current2 = pop (&s2;); current2->left = NULL; inorder(current2); } return ; } if (isEmpty(s2)) { while (!isEmpty(s1)) { current1 = pop (&s1;); current1->left = NULL; inorder(current1); } return ; } // Pop an element from both stacks and compare the // popped elements current1 = pop(&s1;); current2 = pop(&s2;); // If element of first tree is smaller, then print it // and push the right subtree. If the element is larger, // then we push it back to the corresponding stack. if (current1->data < current2->data) { cout<<current1->data<<" "; current1 = current1->right; push(&s2;, current2); current2 = NULL; } else { cout<<current2->data<<" "; current2 = current2->right; push(&s1;, current1); current1 = NULL; } } } } /* Driver program to test above functions */int main() { node *root1 = NULL, *root2 = NULL; /* Let us create the following tree as first tree 3 / \ 1 5 */ root1 = newNode(3); root1->left = newNode(1); root1->right = newNode(5); /* Let us create the following tree as second tree 4 / \ 2 6 */ root2 = newNode(4); root2->left = newNode(2); root2->right = newNode(6); // Print sorted nodes of both trees merge(root1, root2); return 0; } //This code is contributed by rathbhupendra |
C
#include<stdio.h>#include<stdlib.h>// Structure of a BST Nodestruct node{ int data; struct node *left; struct node *right;};//.................... START OF STACK RELATED STUFF....................// A stack nodestruct snode{ struct node *t; struct snode *next;};// Function to add an elemt k to stackvoid push(struct snode **s, struct node *k){ struct snode *tmp = (struct snode *) malloc(sizeof(struct snode)); //perform memory check here tmp->t = k; tmp->next = *s; (*s) = tmp;}// Function to pop an element t from stackstruct node *pop(struct snode **s){ struct node *t; struct snode *st; st=*s; (*s) = (*s)->next; t = st->t; free(st); return t;}// Fucntion to check whether the stack is empty or notint isEmpty(struct snode *s){ if (s == NULL ) return 1; return 0;}//.................... END OF STACK RELATED STUFF..................../* Utility function to create a new Binary Tree node */struct node* newNode (int data){ struct node *temp = (struct node*)malloc(sizeof(struct node)); temp->data = data; temp->left = NULL; temp->right = NULL; return temp;}/* A utility function to print Inoder traversal of a Binary Tree */void inorder(struct node *root){ if (root != NULL) { inorder(root->left); printf("%d ", root->data); inorder(root->right); }}// The function to print data of two BSTs in sorted ordervoid merge(struct node *root1, struct node *root2){ // s1 is stack to hold nodes of first BST struct snode *s1 = NULL; // Current node of first BST struct node *current1 = root1; // s2 is stack to hold nodes of second BST struct snode *s2 = NULL; // Current node of second BST struct node *current2 = root2; // If first BST is empty, then output is inorder // traversal of second BST if (root1 == NULL) { inorder(root2); return; } // If second BST is empty, then output is inorder // traversal of first BST if (root2 == NULL) { inorder(root1); return ; } // Run the loop while there are nodes not yet printed. // The nodes may be in stack(explored, but not printed) // or may be not yet explored while (current1 != NULL || !isEmpty(s1) || current2 != NULL || !isEmpty(s2)) { // Following steps follow iterative Inorder Traversal if (current1 != NULL || current2 != NULL ) { // Reach the leftmost node of both BSTs and push ancestors of // leftmost nodes to stack s1 and s2 respectively if (current1 != NULL) { push(&s1;, current1); current1 = current1->left; } if (current2 != NULL) { push(&s2;, current2); current2 = current2->left; } } else { // If we reach a NULL node and either of the stacks is empty, // then one tree is exhausted, ptint the other tree if (isEmpty(s1)) { while (!isEmpty(s2)) { current2 = pop (&s2;); current2->left = NULL; inorder(current2); } return ; } if (isEmpty(s2)) { while (!isEmpty(s1)) { current1 = pop (&s1;); current1->left = NULL; inorder(current1); } return ; } // Pop an element from both stacks and compare the // popped elements current1 = pop(&s1;); current2 = pop(&s2;); // If element of first tree is smaller, then print it // and push the right subtree. If the element is larger, // then we push it back to the corresponding stack. if (current1->data < current2->data) { printf("%d ", current1->data); current1 = current1->right; push(&s2;, current2); current2 = NULL; } else { printf("%d ", current2->data); current2 = current2->right; push(&s1;, current1); current1 = NULL; } } }}/* Driver program to test above functions */int main(){ struct node *root1 = NULL, *root2 = NULL; /* Let us create the following tree as first tree 3 / \ 1 5 */ root1 = newNode(3); root1->left = newNode(1); root1->right = newNode(5); /* Let us create the following tree as second tree 4 / \ 2 6 */ root2 = newNode(4); root2->left = newNode(2); root2->right = newNode(6); // Print sorted nodes of both trees merge(root1, root2); return 0;} |
Java
public class Merge2BST{ /* A utility function to print Inoder traversal of a Binary Tree */ static void inorder(Node root) { if (root != null) { inorder(root.left); System.out.print(root.data + " "); inorder(root.right); } } // The function to print data of two BSTs in sorted order static void merge(Node root1, Node root2) { // s1 is stack to hold nodes of first BST SNode s1 = new SNode(); // Current node of first BST Node current1 = root1; // s2 is stack to hold nodes of second BST SNode s2 = new SNode(); // Current node of second BST Node current2 = root2; // If first BST is empty, then output is inorder // traversal of second BST if (root1 == null) { inorder(root2); return; } // If second BST is empty, then output is inorder // traversal of first BST if (root2 == null) { inorder(root1); return ; } // Run the loop while there are nodes not yet printed. // The nodes may be in stack(explored, but not printed) // or may be not yet explored while (current1 != null || !s1.isEmpty() || current2 != null || !s2.isEmpty()) { // Following steps follow iterative Inorder Traversal if (current1 != null || current2 != null ) { // Reach the leftmost node of both BSTs and push ancestors of // leftmost nodes to stack s1 and s2 respectively if (current1 != null) { s1.push( current1); current1 = current1.left; } if (current2 != null) { s2.push( current2); current2 = current2.left; } } else { // If we reach a NULL node and either of the stacks is empty, // then one tree is exhausted, ptint the other tree if (s1.isEmpty()) { while (!s2.isEmpty()) { current2 = s2.pop (); current2.left = null; inorder(current2); } return ; } if (s2.isEmpty()) { while (!s1.isEmpty()) { current1 = s1.pop (); current1.left = null; inorder(current1); } return ; } // Pop an element from both stacks and compare the // popped elements current1 = s1.pop(); current2 = s2.pop(); // If element of first tree is smaller, then print it // and push the right subtree. If the element is larger, // then we push it back to the corresponding stack. if (current1.data < current2.data) { System.out.print(current1.data + " "); current1 = current1.right; s2.push( current2); current2 = null; } else { System.out.print(current2.data + " "); current2 = current2.right; s1.push( current1); current1 = null; } } } System.out.println(s1.t); System.out.println(s2.t); } /* Driver code */ public static void main(String[]args) { Node root1 = null, root2 = null; /* Let us create the following tree as first tree 3 / \ 1 5 */ root1 = new Node(3) ; root1.left = new Node(1); root1.right = new Node(5); /* Let us create the following tree as second tree 4 / \ 2 6 */ root2 = new Node(4) ; root2.left = new Node(2); root2.right = new Node(6); // Print sorted nodes of both trees merge(root1, root2); } }// Structure of a BST Nodeclass Node { int data; Node left; Node right; public Node(int data) { // TODO Auto-generated constructor stub this.data = data; this.left = null; this.right = null; }} // A stack node class SNode { SNode head; Node t; SNode next; // Function to add an elemt k to stack void push(Node k) { SNode tmp = new SNode(); // Perform memory check here tmp.t = k; tmp.next = this.head; this.head = tmp; } // Function to pop an element t from stack Node pop() { SNode st; st = this.head; head = head.next; return st.t; } // Fucntion to check whether the stack is empty or not boolean isEmpty( ) { if (this.head == null ) return true; return false; } } // This code is contributed by nidhisebastian008 |
Python 3
# Class to create a new Tree Nodeclass newNode: def __init__(self, data: int): self.data = data self.left = None self.right = Nonedef inorder(root: newNode): if root: inorder(root.left) print(root.data, end=" ") inorder(root.right)def merge(root1: newNode, root2: newNode): # s1 is stack to hold nodes of first BST s1 = [] # Current node of first BST current1 = root1 # s2 is stack to hold nodes of first BST s2 = [] # Current node of second BST current2 = root2 # If first BST is empty then the output is the # inorder traversal of the second BST if not root1: return inorder(root2) # If the second BST is empty then the output is the # inorder traversal of the first BST if not root2: return inorder(root1) # Run the loop while there are nodes not yet printed. # The nodes may be in stack(explored, but not printed) # or may be not yet explored while current1 or s1 or current2 or s2: # Following steps follow iterative Inorder Traversal if current1 or current2: # Reach the leftmost node of both BSTs and push ancestors of # leftmost nodes to stack s1 and s2 respectively if current1: s1.append(current1) current1 = current1.left if current2: s2.append(current2) current2 = current2.left else: # If we reach a NULL node and either of the stacks is empty, # then one tree is exhausted, ptint the other tree if not s1: while s2: current2 = s2.pop() current2.left = None inorder(current2) return if not s2: while s1: current1 = s1.pop() current1.left = None inorder(current1) return # Pop an element from both stacks and compare the # popped elements current1 = s1.pop() current2 = s2.pop() # If element of first tree is smaller, then print it # and push the right subtree. If the element is larger, # then we push it back to the corresponding stack. if current1.data < current2.data: print(current1.data, end=" ") current1 = current1.right s2.append(current2) current2 = None else: print(current2.data, end=" ") current2 = current2.right s1.append(current1) current1 = None# Driver codedef main(): # Let us create the following tree as first tree # 3 # / \ # 1 5 root1 = newNode(3) root1.left = newNode(1) root1.right = newNode(5) # Let us create the following tree as second tree # 4 # / \ # 2 6 # root2 = newNode(4) root2.left = newNode(2) root2.right = newNode(6) merge(root1, root2)if __name__ == "__main__": main()# This code is contributed by Koushik Reddy Bukkasamudram |
C#
// C# program to implement the // above approachusing System;class Merge2BST{ /* A utility function to print Inoder traversal of a Binary Tree */static void inorder(Node root) { if (root != null) { inorder(root.left); Console.Write(root.data + " "); inorder(root.right); } } // The function to print data // of two BSTs in sorted order static void merge(Node root1, Node root2) { // s1 is stack to hold nodes // of first BST SNode s1 = new SNode(); // Current node of first BST Node current1 = root1; // s2 is stack to hold nodes // of second BST SNode s2 = new SNode(); // Current node of second BST Node current2 = root2; // If first BST is empty, then // output is inorder traversal // of second BST if (root1 == null) { inorder(root2); return; } // If second BST is empty, // then output is inorder // traversal of first BST if (root2 == null) { inorder(root1); return ; } // Run the loop while there // are nodes not yet printed. // The nodes may be in stack // (explored, but not printed) // or may be not yet explored while (current1 != null || !s1.isEmpty() || current2 != null || !s2.isEmpty()) { // Following steps follow // iterative Inorder Traversal if (current1 != null || current2 != null) { // Reach the leftmost node of // both BSTs and push ancestors // of leftmost nodes to stack // s1 and s2 respectively if (current1 != null) { s1.push(current1); current1 = current1.left; } if (current2 != null) { s2.push(current2); current2 = current2.left; } } else { // If we reach a NULL node and // either of the stacks is empty, // then one tree is exhausted, // print the other tree if (s1.isEmpty()) { while (!s2.isEmpty()) { current2 = s2.pop (); current2.left = null; inorder(current2); } return; } if (s2.isEmpty()) { while (!s1.isEmpty()) { current1 = s1.pop (); current1.left = null; inorder(current1); } return; } // Pop an element from both // stacks and compare the // popped elements current1 = s1.pop(); current2 = s2.pop(); // If element of first tree is // smaller, then print it // and push the right subtree. // If the element is larger, // then we push it back to the // corresponding stack. if (current1.data < current2.data) { Console.Write(current1.data + " "); current1 = current1.right; s2.push( current2); current2 = null; } else { Console.Write(current2.data + " "); current2 = current2.right; s1.push( current1); current1 = null; } } } Console.Write(s1.t + "\n"); Console.Write(s2.t + "\n");} // Driver code public static void Main(string[]args) { Node root1 = null, root2 = null; /* Let us create the following tree as first tree 3 / \ 1 5 */ root1 = new Node(3) ; root1.left = new Node(1); root1.right = new Node(5); /* Let us create the following tree as second tree 4 / \ 2 6 */ root2 = new Node(4) ; root2.left = new Node(2); root2.right = new Node(6); // Print sorted nodes of // both trees merge(root1, root2); } }// Structure of a BST Nodeclass Node{ public int data; public Node left; public Node right; public Node(int data){ // TODO Auto-generated // constructor stub this.data = data; this.left = null; this.right = null;}} // A stack node class SNode{ SNode head;public Node t;SNode next; // Function to add an element// k to stackpublic void push(Node k) { SNode tmp = new SNode(); // Perform memory check here tmp.t = k; tmp.next = this.head; this.head = tmp;} // Function to pop an element // t from stack public Node pop() { SNode st; st = this.head; head = head.next; return st.t; } // Fucntion to check whether // the stack is empty or not public bool isEmpty() { if (this.head == null ) return true; return false; } } // This code is contributed by Rutvik_56 |
1 2 3 4 5 6
Time Complexity: O(m+n)
Auxiliary Space: O(height of the first tree + height of the second tree)
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.

