Встроенный API максимальной кучи в Python
По умолчанию heapq - это реализация очереди min и интересно, есть ли опция для максимальной очереди? Спасибо.
Я попробовал решение с помощью _heapify_max для максимальной кучи, но как обрабатывать динамический элемент push/pop? Кажется, что _heapify_max можно использовать только во время инициализации.
import heapq
def heapsort(iterable):
h = []
for value in iterable:
heapq.heappush(h, value)
return [heapq.heappop(h) for i in range(len(h))]
if __name__ == "__main__":
print heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8, 0])
Изменить, попробовал _heapify_max, похоже, не работает для динамических кнопок push/pop. Я попробовал оба метода вывода одинаково, оба выхода - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].
def heapsort(iterable):
h = []
for value in iterable:
heapq.heappush(h, value)
return [heapq.heappop(h) for i in range(len(h))]
def heapsort2(iterable):
h = []
heapq._heapify_max(h)
for value in iterable:
heapq.heappush(h, value)
return [heapq.heappop(h) for i in range(len(h))]
if __name__ == "__main__":
print heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8, 0])
print heapsort2([1, 3, 5, 7, 9, 2, 4, 6, 8, 0])
Спасибо заранее,
Lin
Ответы
Ответ 1
В прошлом я просто использовал sortedcontainers SortedList
для этого, как:
> a = SortedList()
> a.add(3)
> a.add(2)
> a.add(1)
> a.pop()
3
Это не куча, но она быстро и работает напрямую по мере необходимости.
Если вам абсолютно необходимо, чтобы это была куча, вы могли бы сделать общий класс отрицания, чтобы держать ваши предметы.
class Neg():
def __init__(self, x):
self.x = x
def __cmp__(self, other):
return -cmp(self.x, other.x)
def maxheappush(heap, item):
heapq.heappush(heap, Neg(item))
def maxheappop(heap):
return heapq.heappop(heap).x
Но это будет использовать немного больше памяти.
Ответ 2
Существует функция _ heappop_max в последнем источнике cpython, который может оказаться полезным:
def _heappop_max(heap):
"""Maxheap version of a heappop."""
lastelt = heap.pop() # raises appropriate IndexError if heap is empty
if heap:
returnitem = heap[0]
heap[0] = lastelt
heapq._siftup_max(heap, 0)
return returnitem
return lastelt
Если вы измените логику heappush
, используя heapq._siftdown_max
, вы должны получить желаемый результат:
def _heappush_max(heap, item):
heap.append(item)
heapq._siftdown_max(heap, 0, len(heap)-1)
def _heappop_max(heap):
"""Maxheap version of a heappop."""
lastelt = heap.pop() # raises appropriate IndexError if heap is empty
if heap:
returnitem = heap[0]
heap[0] = lastelt
heapq._siftup_max(heap, 0)
return returnitem
return lastelt
def heapsort2(iterable):
h = []
heapq._heapify_max(h)
for value in iterable:
_heappush_max(h, value)
return [_heappop_max(h) for i in range(len(h))]
Вывод:
In [14]: heapsort2([1,3,6,2,7,9,0,4,5,8])
Out[14]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
In [15]: heapsort2([7, 8, 9, 6, 4, 2, 3, 5, 1, 0])
Out[15]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
In [16]: heapsort2([19,13,15,17,11,10,14,20,18])
Out[16]: [20, 19, 18, 17, 15, 14, 13, 11, 10]
In [17]: heapsort2(["foo","bar","foobar","baz"])
Out[17]: ['foobar', 'foo', 'baz', 'bar']