Как я понимаю, binary heap
не поддерживает удаление случайных элементов. Что делать, если мне нужно удалить случайные элементы из binary heap
?
Очевидно, я могу удалить элемент и переустановить всю кучу в O(N)
. Могу ли я сделать лучше?
Как я понимаю, binary heap
не поддерживает удаление случайных элементов. Что делать, если мне нужно удалить случайные элементы из binary heap
?
Очевидно, я могу удалить элемент и переустановить всю кучу в O(N)
. Могу ли я сделать лучше?
Да и нет.
Проблема заключается в двоичной куче, которая не поддерживает поиск для произвольного элемента. Поиск сам по себе O(n)
.
Однако, если у вас есть указатель на элемент (и не только его значение) - , вы можете поменять элемент с помощью самого правильного листа, удалите этот лист, а затем повторно запустите -heap (путем отсеивания вновь размещенного элемента столько, сколько необходимо). Это приводит к удалению O(logn)
, но требует указателя на фактический элемент, который вы ищете.
Амит прав в своем ответе, но вот еще один нюанс:
позиция удаляемого элемента (где вы помещаете правый лист) может потребоваться, чтобы пузыряться (сравните с родителем и двигайтесь вверх, пока родитель больше вас). Иногда требуется пузыриться (сравните с детьми и двигайтесь вниз, пока все дети не станут меньше вас). Все зависит от случая.
Зависит от того, что подразумевается под "случайным элементом". Если это означает, что куча содержит элементы [e1, e2,..., eN] и хочет удалить некоторое ei (1 <= я <= N), тогда это возможно.
Если вы используете реализацию двоичной кучи из какой-либо библиотеки, возможно, она не предоставляет вам API, который вам нужен. В этом случае вы должны искать другую библиотеку, которая имеет его.
Если вы должны были реализовать его самостоятельно, вам понадобятся два дополнительных вызова:
Процедура deleteAtIndex (heap, i), которая удаляет node по индексу i путем позиционирования последнего элемента в массиве кучи в i, уменьшая количество элементов и, наконец, перетасовка вниз/вверх новый i-й элемент для поддержания инварианта кучи. Большинство Обычное использование этой процедуры заключается в том, чтобы "выскочить" из кучи, вызвав deleteAtIndex (heap, 1) - при условии индексации 1-начала. Эта операция будет работать O (log n) (хотя, чтобы быть полным, я отмечу, что самая высокая граница может быть улучшено до O (log (log n)) в зависимости от некоторых допущений о ключах ваших элементов.
Процедура deleteElement (heap, e), которая удаляет элемент e (ваш произвольный элемент). Ваш алгоритм кучи будет поддерживать массив ElementIndex таким образом, чтобы ElementIndex [e] возвращался текущий индекс элемента e: вызов deleteAtIndex (heap, ElementIndex [e]) будет делать то, что вы хотите. Он также будет работать в O (log n), поскольку доступ к массиву постоянный.
Так как двоичные кучи часто используются в алгоритмах, которые просто выставляют наивысший (или самый низкий) (а не удалять произвольные элементы), я полагаю, что некоторые библиотеки могут пропустить API-интерфейс deleteAtIndex для экономии места (дополнительный массив ElementIndex, упомянутый выше).