web-dev-qa-db-ja.com

Pythonの組み込み最大ヒープAPI

デフォルトのheapqは最小キュー実装であり、最大キューのオプションがあるかどうか疑問に思っていますか?ありがとう。

最大ヒープに_heapify_maxを使用してソリューションを試しましたが、プッシュ/ポップ要素を動的に処理する方法は? _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は、動的にプッシュ/ポップ要素に対して機能していないようです。私は両方の方法の出力を同じにしてみましたが、両方の出力は[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])

事前に感謝、リン

23
Lin Ma

過去に、私は単に sortedcontainersSortedListを次のように使用しました。

> 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

しかし、それはもう少しメモリを使用します。

24
U2EF1

最新のcpythonソースには、役に立つかもしれない _ heappop_max 関数があります:

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

heapq._siftdown_maxを使用してheappushロジックを変更すると、目的の出力が得られます。

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']
5