27

How to merge two binary search trees maintaining the property of BST?

If we decide to take each element from a tree and insert it into the other, the complexity of this method would be O(n1 * log(n2)), where n1 is the number of nodes of the tree (say T1), which we have splitted, and n2 is the number of nodes of the other tree (say T2). After this operation only one BST has n1 + n2 nodes.

My question is: can we do any better than O(n1 * log(n2))?

3
  • 6
    Inserting the root of tree 1 into tree 2 will not work in every case. Commented Jun 17, 2009 at 17:45
  • 3
    You are making the assumption that all binary search trees are balanced. (For instance Splay trees are not) Also I think your complexity is slightly off. Because n2 is increasing, the tree will get deeper as you insert values. Maybe (n1 + n2) / 2 is a better approximation (Because at the beginning of the insert it is O(log n2) to insert and at the end it is O(log(n1 + n2)).
    – jabbie
    Commented Jun 18, 2009 at 0:50
  • @Evan Teran, a<-c->h union b<-d->f for instance, their ranges [a,h] and [b,f] overlap and thus neither can be inserted into another as a leaf node Commented Apr 15, 2013 at 22:55

6 Answers 6

27

Naaff's answer with a little more details:

  • Flattening a BST into a sorted list is O(N)
    • It's just "in-order" iteration on the whole tree.
    • Doing it for both is O(n1+n2)
  • Merging two sorted lists is into one sorted list is O(n1+n2).
    • Keep pointers to the heads of both lists
    • Pick the smaller head and advance its pointer
    • This is how the merge of merge-sort works
  • Creating a perfectly balanced BST from a sorted list is O(N)
    • See code snippet below for algorithm[1]
    • In our case the sorted list is of size n1+n2. so O(n1+n2)
    • The resulting tree would be the conceptual BST of binary searching the list

Three steps of O(n1+n2) result in O(n1+n2)

For n1 and n2 of the same order of magnitude, that's better than O(n1 * log(n2))

[1] Algorithm for creating a balanced BST from a sorted list (in Python):

def create_balanced_search_tree(iterator, n):
    if n == 0:
        return None
    n_left = n//2
    n_right = n - 1 - n_left
    left = create_balanced_search_tree(iterator, n_left)
    node = iterator.next()
    right = create_balanced_search_tree(iterator, n_right)
    return {'left': left, 'node': node, 'right': right}
4
  • 2
    Sketch of proof that you can't improve on that: You need to consider each element. Between 2 adjacent values in tree 1 there might be 0,1 or more values to be found in tree 2. Just looking at N1+N2 elements already takes O(N1+N2) time.
    – MSalters
    Commented Jun 18, 2009 at 9:09
  • 1
    @MSalters: according to OP you are allowed to modify one tree in-place. you don't have to look at all the elements of the tree you are modifying
    – yairchu
    Commented Jun 18, 2009 at 11:29
  • I am having some difficulty in understanding how the last step of creating the balanced BST is O(N). Since the data structure used here is a list, won't the complexity of finding the 'middle' for the n elements at each level of the recursion, be n/2 ? So the total complexity of the creating the balanced BST would be n/2 log n, right ? If the sorted data was in an array I can see how this can be done in O(N). But that is not the case here. What am I missing?
    – Karthik M
    Commented Jun 29, 2018 at 16:31
  • @KarthikM: My explanation was indeed not too accurate, added the algorithm with an actual code snippet to the answer now.
    – yairchu
    Commented Jul 1, 2018 at 8:00
21
  • Flatten trees into sorted lists.
  • Merge sorted lists.
  • Create tree out of merged list.

IIRC, that is O(n1+n2).

0
10

What about flattening both trees into sorted lists, merging the lists and then creating a new tree?

2
  • 1
    As others have pointed out after my post, the complexity of this procedure is O(n1+n2). For example, see yairchu's elaboration on my answer.
    – Naaff
    Commented Jun 18, 2009 at 0:30
  • 4
    infinite redirection loop between your post and @yairchu. Commented Jan 25, 2016 at 20:02
1

Jonathan,

After sorting, we have a list of length n1+n2. Building a binary tree out of it will take log(n1+n2) time. This is same as merge sort, only that at each recursive step we wont have a O(n1+n2) term as we have in merge sort algorithm . So the time complexity is log(n1+n2).

Now the complexity of the whole problem is O(n1+n2).

Also I would say this approach is good if two lists are comparable size. If the sizes are not comparable then it is best to insert every node of the small tree into a large tree. This would take O(n1*log(n2)) time. For example if we have two trees one of size 10 and another of size 1024. Here n1+n2 = 1034 where as n1log(n2) = 10*10 = 100. So approach has to depend upon the sizes of the two trees.

1
  • I mean building a tree with sorted list is of complexity log(n1+n2). Now the complexity of the whole problem is O(n1+n2)
    – genthu
    Commented Jul 27, 2010 at 21:09
0

O(n1 * log(n2)) is the average case scenario even if we have 2 merge any unsorted list into a BST. We are not utilizing the fact that list is sorted list or a BST.

According to me Lets assume one BST has n1 elements and other has n2 elements. Now convert one BST into a Sorted Array List L1 in O(n1).

Merged BST(BST, Array)

if (Array.size == 0) return BST if(Array.size ==1) insert the element in the BST. return BST;

Find the index in the array whose left element < BST.rootnode and right element >=BST.rootnode say Index. if(BST.rootNode.leftNode ==null ) //i.e No left node { insert all the array from Index to 0 into left of BST and } else { Merged BST(BST.leftNode, Array{0 to Index}) }

if(BST.rootNode.rightNode ==null)//i.e No right node { insert all the array from Index to Array.size into right of BST } else { Merged BST(BST.rightNode, Array{Index to Array.size}) }

return BST.

This algorithm will take << time than O(n1 * log(n2)) as every time we are partitioning the array and BST to handle the subproblem.


0

The idea is to use iterative inorder traversal. We use two auxiliary stacks for two BSTs. Since we need to print the elements in 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.

1
  • Double iterative inorder traversal could work, but what are you on about regarding printing out the elements? You're supposed to end up with a BST. Commented May 25, 2014 at 21:37

Not the answer you're looking for? Browse other questions tagged or ask your own question.