Объединение/слияние / объединение двух деревьев AVL

предположим, что у меня есть два дерева AVL и что каждый элемент из первого дерева меньше любого элемента из второго дерева. Каков наиболее эффективный способ объединить их в одно дерево AVL? Я искал везде но не нашел ничего полезного.

4 ответов


предполагая, что вы можете уничтожить входные деревья:

  1. удалите самый правый элемент для левого дерева и используйте его для создания нового корневого узла, левый дочерний элемент которого является левым деревом, а правый дочерний элемент-правым деревом: O (log n)
  2. определите и установите коэффициент баланса этого узла: O (log n). При (временном) нарушении инварианта коэффициент баланса может находиться вне диапазона {-1, 0, 1}
  3. поверните, чтобы вернуть коэффициент баланса в диапазон: O (log N) вращения: O (log n)

таким образом, вся операция может быть выполнена в O(log n).

Edit: с другой стороны, легче рассуждать о вращениях в следующем алгоритме. Это также, скорее всего, быстрее:

  1. определите высоту обоих деревьев: O (log n).
    Предполагая, что правое дерево выше (другой случай симметричен):
  2. удалить правый элемент left дерево (вращение и регулировка его вычисленная высота при необходимости). Пусть n быть этот элемент. O (log n)
  3. в правом дереве перейдите влево, пока не достигнете узла, поддерево которого не более 1 выше left. Пусть r быть этот узел. O (log n)
  4. замените этот узел новым узлом со значением n и поддеревьями left и r. O (1)
    По конструкции новый узел AVL-сбалансирован, а его поддерево 1 выше r.

  5. приращение его баланс родителей соответственно. O (1)

  6. и перебалансировки, как вы бы после вставки. O (log n)

одно ультра простое решение (которое работает без каких-либо предположений в отношениях между деревьями) заключается в следующем:

  1. выполните слияние обоих деревьев в один объединенный массив (одновременно повторите оба дерева).
  2. создайте дерево AVL из массива-возьмите средний элемент как корень и примените рекурсивно к левой и правой половинам.

оба шага O (n). Основная проблема заключается в том, что он занимает o(n) дополнительное пространство.


лучшее решение, которое я прочитал для этой проблемы, можно найти здесь. Очень близко к Меритонответ, если вы исправите этот вопрос:

на третьем шаге алгоритма перемещается влево, пока вы не достигнете узла, под дерево которого имеет ту же высоту, что и левое дерево. Это не всегда возможно (см. контрпример image). Правильный способ сделать этот шаг-найти два поддерева с высотой h или h+1 здесь h - Это высота левого дерева counterexample


Я подозреваю, что вам просто придется ходить по одному дереву (надеюсь, меньшему) и индивидуально добавлять каждый из его элементов к другому дереву. Операции вставки/удаления AVL не предназначены для обработки добавления целого поддерева за раз.