5

Assume that I have two AVL trees and that I know their respective sizes. However, I don't know if there are repeated nodes, or any other information. What would be the most efficient way to merge them in a new AVL tree? The original trees can be destroyed.

Josep
  • 12,515
  • 2
  • 39
  • 44
  • 5
    possible duplicate http://stackoverflow.com/questions/2037212/concatenating-merging-joining-two-avl-trees – Rohan Monga Dec 16 '10 at 07:52
  • 5
    That's not exactly a duplicate. The conditions in your link are more restricted: "each element from the first tree is smaller then any element from the second tree" – Juraj Blaho Dec 16 '10 at 08:58
  • 1
    @bronzebeard: The questions are different. The one pointed by you has a condition that greatly simplifies the problem and its solutions are not applicable here. – salva Dec 16 '10 at 09:15

2 Answers2

5
  1. Convert your trees T1 and T2 to sorted lists L1 and L2
  2. Merge L1 and L2 into a sorted list L
  3. Convert L into a tree T again.

IIRC all this operations are O(N), so the full merge will also be O(N).

If your representation of AVL trees allows to iterate over them efficiently (for instance, using backpointers, continuations, lazy evaluation, etc.) you should be able to do it also without the intermediate lists.

Update: as your programming language seems to be C/C++ you could temporarily abuse your AVL node estructures to be nodes in a linked list and later reuse them again for the output tree.

Update 2: @hwlau: this is O(N), I have checked it using my own AVL implementation in Prolog available from avl.pl and this test program avl_test.pl that checks the number of operations when merging AVL trees of size 1, 2, 4, 8, 16, ...

This is the output:

timing avl_merge, size: 128
% 1,790 inferences, 0.000 CPU in 0.001 seconds (0% CPU, Infinite Lips)
timing avl_merge, size: 256
% 3,591 inferences, 0.010 CPU in 0.002 seconds (430% CPU, 359100 Lips)
timing avl_merge, size: 512
% 7,176 inferences, 0.030 CPU in 0.028 seconds (107% CPU, 239200 Lips)
...
timing avl_merge, size: 32000
% 451,839 inferences, 0.490 CPU in 0.499 seconds (98% CPU, 922120 Lips)
timing avl_merge, size: 64000
% 903,682 inferences, 0.900 CPU in 0.964 seconds (93% CPU, 1004091 Lips)
timing avl_merge, size: 128000
% 1,807,363 inferences, 2.420 CPU in 2.559 seconds (95% CPU, 746844 Lips)

Its obvious that the number of inferences/operations is proportional to the size of the merged trees and so the complexity of the algorithm O(N).

salva
  • 9,300
  • 3
  • 24
  • 55
  • I want to know how to convert a list to a tree in O(N) time :) – unsym Dec 16 '10 at 10:03
  • @hwlau: I am almost sure you can convert a *sorted* list to a tree in O(N). – salva Dec 16 '10 at 10:27
  • @salva: I think you can't convert list in O(N), but you can convert a vector. – Juraj Blaho Dec 16 '10 at 11:25
  • 1
    @Juraj Blaho: if you can convert a vector to an AVL in O(N) you can also convert a list to an AVL in O(N) as converting a list to a vector is also an O(N) operation! – salva Dec 16 '10 at 11:38
  • @salva: Sor, so the algorithm is to put the middle element as root and preform the recursive operations on the left and right sorted elements, so it is O(N). I am not sure with the implementation of the backpointers, whether it allows you to construct in linear time. And one more comment, you last three data seems runtime > N. – unsym Dec 16 '10 at 13:01
  • If you know "respective sizes" of both trees the method you gave isn't "the most efficient way". Proof: tree A have 1000 nodes, tree B have 3 nodes. Plain insertion of 3 nodes takes 3*O(log 1000), which is much less than your approach: O(1000) + O(3). – Yuri Yaryshev Mar 31 '19 at 09:45
2

It is not the most efficient, but is definitely the easiest to implement. You can just add all nodes from second tree to the first. You don't need to remove the nodes from the second tree. You just destroy the second tree then and have the first tree as a result. The time complexity is O(N*log(N)).

Juraj Blaho
  • 12,713
  • 5
  • 46
  • 92
  • Strictly, the complexity of this method is O(M*log(N+M)). This method can be appropriate when one of the trees is much smaller than the other. – salva Dec 16 '10 at 11:42
  • In fact this method performs faster than @salva proposed in some situations, suppose you have tree A with 1000 nodes and tree B with 3 nodes. Your method would require just 3 iterations, while salva's would require at least (1000+3) iterations. – Yuri Yaryshev Mar 31 '19 at 09:49
  • @YuriYaryshev, that's exactly what my previous comment says, right? – salva Apr 01 '19 at 10:26