Я пытаюсь реализовать приоритетную очередь как минимальную двоичную кучу с отсортированным массивом. Я пытаюсь заставить функцию update_key работать за логарифмическое время, но для этого мне нужно знать позицию элемента в массиве. Можно ли как-то это сделать без использования карты? Если да, то как? Спасибо
Приоритетная очередь — двоичная куча
Ответы (3)
Если вы действительно хотите иметь возможность изменить ключ произвольного элемента, куча — не лучший выбор структуры данных. Что это дает вам, так это сочетание:
- компактное представление (без указателей, только массив и неявная схема индексации)
- логарифмическая вставка, перебалансировка
- логарифмическое удаление наименьшего (наибольшего) элемента.
- O(1) доступ к значению наименьшего (наибольшего) элемента. -
Дополнительным преимуществом 1. является то, что отсутствие указателей означает, что вы делаете значительно меньше вызовов malloc/free
(new/delete
). Карта (представленная в стандартной библиотеке в виде сбалансированного двоичного дерева) дает вам два средних из них, добавляя в
- логарифмический
find()
по любому ключу.
Таким образом, хотя вы можете присоединить другую структуру данных к своей куче, сохраняя указатели в куче, а затем выполняя разыменование оператора сравнения через указатель, вы довольно скоро обнаружите сложность во времени и пространстве, просто используя map
в первом место.
Ваша функция поиска ключа должна работать за логарифмическое время. Ваше обновление (смена ключа) должно происходить постоянно. Ваша функция удаления должна выполняться за время log(n). Ваша функция вставки должна быть log(n) раз.
Если эти предположения верны, попробуйте следующее: 1) Найдите свой элемент в своей куче (IE: двоичный поиск, поскольку это отсортированный массив). 2) Обновите свой ключ (вы просто меняете значение, постоянное время). 3) Удалите элемент из журнала кучи (n) для повторной кучи.
4) Вставьте свой элемент в журнал кучи (n).
Итак, у вас будет log(n) + 1 + log(n) + log(n), что сводится к log(n).
Примечание: это амортизируется, потому что, если вам нужно перераспределить свой массив и т. Д., Это добавляет накладные расходы. Но в любом случае не стоит делать это слишком часто.
Это компромисс кучи, поддерживаемой массивом: вы получаете отличное использование памяти (хорошее расположение и минимальные накладные расходы), но вы теряете элементы. Чтобы решить эту проблему, вы должны добавить некоторые накладные расходы.
Одним из решений было бы это. Куча содержит объекты типа C*
. C — это класс с int
членом heap_index
, который является индексом объекта в массиве кучи. Всякий раз, когда вы перемещаете элемент внутри массива кучи, вам придется обновить его heap_index
, чтобы установить для него новый индекс.
Update_key (а также удаление произвольного элемента) в этом случае занимает время log(n), потому что требуется постоянное время, чтобы найти элемент (через heap_index
), и log(n) время, чтобы переместить его в правильную позицию.