Конкатенация/слияние/объединение двух деревьев AVL

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


person liviucmg    schedule 10.01.2010    source источник
comment
Спасибо за отличный вопрос, но я думаю, что он больше подходит для: cs.stackexchange.com   -  person ChaosPredictor    schedule 12.02.2018


Ответы (4)


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

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

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

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

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

  5. соответственно увеличить баланс своего родителя. О(1)

  6. и перебалансируйте, как после вставки. О (журнал п)
person meriton    schedule 10.01.2010
comment
Вы уверены? (Возможно, вы правы, но мне просто любопытно.) Предположим, что левое дерево намного меньше правого, т. е. намного мельче. Почему O (log n) поворотов восстановит свойство AVL? Как вы решаете, где вращаться? - person Dale Hagglund; 10.01.2010
comment
Что говорит Дейл: обычный выбор вращений для дерева AVL позволяет скорректировать дисбаланс размера 2 обратно в диапазон [-1,1] с O (log n) вращений. Нужна новая схема выбора вращений, чтобы исправить произвольный дисбаланс. Поскольку это та часть деревьев AVL, которую я никогда не могу вспомнить, и мне приходится каждый раз искать, я ожидаю, что даже если выбор поворотов очевиден, он не очевиден для меня :-) - person Steve Jessop; 10.01.2010
comment
Хорошие моменты. Мне было легче доказать другой алгоритм (см. мой отредактированный ответ). - person meriton; 10.01.2010
comment
Спасибо за Ваш ответ. Это сработало! Одна вещь, однако, в точке 3 вам нужно перемещаться влево, пока вы не достигнете узла с 'node.height ‹= left_tree.height + 1'. - person liviucmg; 11.01.2010
comment
Мне потребовалось некоторое время, чтобы разобрать, что вы имели в виду, заменив этот узел на (слева, n, r). Подумайте о перефразировании. - person ripper234; 18.01.2011
comment
@meriton, я согласен с ripper234 - person Jackson Tale; 07.03.2012
comment
Действительно очень хороший ответ. - person axel22; 30.07.2014
comment
Я считаю, что в вашем ответе неправильная деталь. На третьем шаге вашего последнего алгоритма вы двигаетесь влево, пока не достигнете узла, поддерево которого имеет ту же высоту, что и левое дерево. Пусть r будет этим узлом. Это не всегда возможно, контрпример здесь. Правильный способ выполнить этот шаг — найти два поддерева высотой h или h+1, где h — высота левого дерева. - person rareyesdev; 29.10.2014
comment
Для шага 2 следует ли перебалансировать узлы в левом дереве после удаления n? - person Lukazoid; 06.07.2017
comment
Да, конечно; в противном случае результирующее дерево не будет сбалансировано по AVL. Отредактировал, чтобы уточнить. Пока я занимался этим, я также включил отзывы @agarwaen. - person meriton; 07.07.2017
comment
Это немного поздно, учитывая возраст поста, но может ли кто-нибудь объяснить шаг 6. Я понимаю, как вы будете перебалансировать после вставки узла, но как это будет работать после вставки поддерева? - person Geralt; 24.01.2020

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

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

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

person ripper234    schedule 17.01.2011
comment
Разве первый шаг не O(n log(n))? - person technical_difficulty; 09.12.2017
comment
Основная проблема заключается в том, что оно не является логарифмическим по времени. - person enedil; 05.12.2018

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

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

person rareyesdev    schedule 29.10.2014

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

person Dale Hagglund    schedule 10.01.2010
comment
У меня есть ощущение, что это можно сделать линейно. Использование наивного подхода требует времени O(n log n). - person avakar; 10.01.2010
comment
Это занимает O (n log n) -> намного медленнее, чем решение Меритона. - person inspectorG4dget; 12.02.2010
comment
Решение @meriton действительно очень хорошее, но оно предполагает (а) что каждый узел в одном дереве строго меньше, чем каждый узел в другом дереве, (б) у вас есть доступ к необработанным структурам данных дерева avl и (в) можно выполнять повороты непосредственно на узлах дерева. Если (a) не выполняется или низкоуровневые манипуляции с деревом недоступны для вас (скорее всего, потому что вы используете библиотеку avl), вам, возможно, придется вернуться к простой вставке каждого узла из меньшего дерева в чем больше. - person Dale Hagglund; 13.02.2010