Как удалить элементы из двоичной кучи?

как я понимаю, binary heap не поддерживает удаление случайных элементов. Что делать, если мне нужно удалить случайные элементы из binary heap?

очевидно, я могу удалить элемент и переставить всю кучу в O(N). Могу я сделать лучше?

3 ответов


да и нет.

проблема двоичная "куча" не поддерживает поиск для произвольного элемента. Найти ее сам O(n).

однако, если у вас есть указатель на элемент (и не только его стоимости) - вы можете поменять элемент с самым правым листом, удалить этот лист, и чем re-heapify соответствующая под-куча (путем просеивания вновь размещенного элемента столько, сколько необходимо). Это приводит к O(logn) удаление, но требуется указатель фактический элемент, который вы ищете.


Амит прав в своем ответе, но вот еще один нюанс:

положение удаленного элемента (где вы положили самый правый лист) может потребоваться, чтобы быть пузырится (сравните с родителем и двигаться вверх, пока родитель больше, чем вы). Иногда требуется пузыриться вниз (сравните с детьми и двигайтесь вниз, пока все дети не станут меньше вас). Все зависит от дела.


зависит от того, что подразумевается под "случайный элемент."Если это означает, что куча содержит элементы [e1, e2,..., eN] и нужно удалить некоторые ei (1

Если вы используете двоичную реализацию кучи из некоторой библиотеки, возможно, она не предоставляет вам API, который вам нужен. В этом случае вы должны искать другую библиотеку, в которой она есть.

Если бы вы должны были реализовать его самостоятельно, вам понадобилось бы два дополнительных звонки:

  1. процедура deleteAtIndex (heap, i), которая удаляет узел в индексе i расположив последний элемент в массиве кучи на i, уменьшив количество элементов и, наконец, перетасовка вниз / вверх новый I-й элемент для поддержания инварианта кучи. Самый обычно эта процедура используется для " pop " кучи путем вызова deleteAtIndex (heap, 1) -- предполагая индексирование 1-origin. Эта операция будет выполняться O (log n) (хотя, чтобы быть полным, я отмечу, что самая высокая граница может быть улучшено до O (log (log n)) в зависимости от некоторых предположений о ключах ваших элементов).

  2. процедура deleteElement (heap, e), которая удаляет элемент e (ваш произвольный элемент). Ваш алгоритм кучи будет поддерживать массив ElementIndex таким образом, что ElementIndex [e] возвращает текущий индекс элемента e: вызов deleteAtIndex (heap, ElementIndex[e]) тогда делайте, что хотите. Он также будет работать в O (log n), потому что доступ к массиву постоянный.

Так как двоичные кучи часто используются в алгоритмах, которые просто поп-самый высокий (или самый низкий) элемент приоритета (а не удаление произвольных элементов), я полагаю, что некоторые библиотеки могут пропустить API deleteAtIndex для экономии места (дополнительный массив ElementIndex, упомянутый выше).