Подтвердить что ты не робот

Как я могу реализовать функциональные возможности сокращения в Python heapq?

Я знаю, что в O (log n) можно реализовать функциональность уменьшения ключа, но я не знаю, как?

4b9b3361

Ответ 1

Чтобы эффективно реализовать "уменьшающий ключ", вам нужно получить доступ к функциональности "уменьшить этот элемент и заменить этот элемент дочерним, пока не будет восстановлено состояние кучи". В heapq.py, который называется _siftdown (и аналогичным образом _siftup для INcrementing). Таким образом, хорошая новость заключается в том, что функции существуют... Плохая новость заключается в том, что их имена начинаются с подчеркивания, указывая, что они считаются "внутренними деталями реализации" и не должны быть доступны напрямую по коду приложения (следующий выпуск стандартная библиотека может изменить ситуацию и сломать код с помощью таких "внутренних" ).

Вам решать, следует ли игнорировать предупреждение, ведущее- _, использовать O (N) heapify вместо O (log N) sifting или переопределить некоторые или все функции heapq, чтобы сделать просеивающие примитивы ", выставленные как открытые части интерфейса". Поскольку структура данных heapq документирована и общедоступна (просто список), я думаю, что лучший выбор, вероятно, является частичным повторным выполнением - по существу, скопируйте функции отсеивания из heapq.py в ваш код приложения.

Ответ 2

документация heapq содержит запись о том, как это сделать.

Однако я написал пакет heap, который делает именно это (это обертка вокруг heapq). Поэтому, если у вас есть pip или easy_install, вы можете сделать что-то вроде

pip install heap

Затем в вашем коде напишите

from heap.heap import heap

h = heap()

h['hello'] = 4 # Insert item with priority 4.

h['hello'] = 2 # Update priority/decrease-key has same syntax as insert. 

Это довольно ново, так что может быть множество ошибок.

Ответ 3

Представьте, что вы используете кучу в качестве очереди приоритетов, где у вас есть множество задач, представленных строками, и каждая задача имеет ключ. Для конкретности посмотрите: task_list = [[7,"do laundry"], [3, "clean room"], [6, "call parents"]] где каждая задача в task_list - это список с приоритетом и описанием. Если вы запустите heapq.heapify(task_list), вы получите массив для сохранения инварианта кучи. Однако, если вы хотите изменить приоритет "сделать стирку" на 1, вы не можете узнать, где "сделать белье" находится в куче без линейного сканирования через кучу (следовательно, он не может делать drop_key в логарифмическом времени), Примечание decrease_key(heap, i, new_key) требует, чтобы вы указали индекс значения для изменения в куче.

Даже если вы сохраняете ссылку на каждую подсписку и на самом деле меняете ключ, вы все равно не сможете это сделать в журнале. Поскольку список - это просто ссылка на кучу изменчивых объектов, вы можете попытаться сделать что-то вроде запоминания первоначального порядка задачи: (в этом случае "сделать стирку" было 0-й задачей в вашем оригинале task_list):

task_list = [[7, "do laundry"], [3, "clean room"], [6, "call parents"]]
task_list_heap = task_list[:] # make a non-deep copy
heapq.heapify(task_list_heap)
# at this point:
# task_list = [[7, 'do laundry'], [3, 'clean room'], [6, 'call parents']]
# task_list_heap = [3, 'clean room'], [7, 'do laundry'], [6, 'call parents']]
# Change key of first item of task_list (which was "do laundry") from 7 to 1.
task_list[0][0] = 1
# Now:
# task_list = [[1, 'do laundry'], [3, 'clean room'], [6, 'call parents']]
# task_list_heap = [3, 'clean room'], [1, 'do laundry'], [6, 'call parents']]
# task_list_heap violates heap invariant at the moment

Однако теперь вам нужно вызвать heapq._siftdown(task_list_heap, 1) для поддержания инварианта кучи в лог-времени (heapq.heapify является линейным временем), но, к сожалению, мы не знаем индекса "сделать стирку" в task_list_heap (heap_index в этом случае 1).

Итак, нам нужно реализовать, что наша куча отслеживает heap_index каждого объекта; например, иметь list (для кучи) и dict сопоставление каждого объекта с его индексом в списке кучи/списка (который обновляется по мере того, как позиции кучи меняются местами, добавляя постоянный коэффициент для каждого свопа). Вы можете прочитать heapq.py и реализовать себя, поскольку процедура проста; однако другие уже реализуют этот вид HeapDict.

Ответ 4

Клавиша уменьшения - обязательная операция для многих алгоритмов (Dijkstra Algorithm, A *, OPTICS), мне интересно, почему встроенная очередь приоритетов Python не поддерживает ее.

К сожалению, я не смог загрузить пакет math4tots.

Но я смог найти эту реализацию Daniel Stutzbach. Работала отлично для меня с Python 3.5.