Python'da bir maksimum yığın uygulaması için ne kullanırım?


Yanıtlar:


244

En kolay yol, anahtarların değerini tersine çevirmek ve heapq kullanmaktır. Örneğin, 1000.0'ı -1000.0'a ve 5.0'ı -5.0'a dönüştürün.


38
Aynı zamanda standart çözümdür.
Andrew McGregor

44
uggh; toplam çamur. Ben heapqbir ters sağlamaz sürpriz .
shabbychef

40
Vay. Bunun sağlanmamasına ve iyi bir alternatifin bulunmamasına şaşırdımheapq .
ire_and_curses

23
@gatoatigrado: Kolayca int/ ile eşleşmeyen bir şeyiniz varsa float, ters çevrilmiş bir işleçle bir sınıfa sarıp sıralamayı tersine çevirebilirsiniz __lt__.
Daniel Stutzbach

5
@Aerovistae aynı tavsiye geçerlidir: başlangıçta pozitif veya negatif olursa olsun değerleri ters çevirin (yani işareti değiştirin).
Dennis

235

Kullanabilirsiniz

import heapq
listForTree = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]    
heapq.heapify(listForTree)             # for a min heap
heapq._heapify_max(listForTree)        # for a maxheap!!

Daha sonra öğeleri açmak istiyorsanız, şunu kullanın:

heapq.heappop(minheap)      # pop from minheap
heapq._heappop_max(maxheap) # pop from maxheap

34
Dış görünüş maksimum yığın için bazı belgesiz fonksiyonları vardır gibi: _heapify_max, _heappushpop_max, _siftdown_max, ve _siftup_max.
ziyuang

127
Vay. Ben ediyorum hayrete oradaki IS böyle yerleşik bir heapq içinde çözelti. Ama sonra tamamen olduğunu mantıksız o olduğunu DEĞİL hatta biraz resmi belgede hiç söz! O NE LAN!
RayLuo

27
Pop / push işlevlerinden herhangi biri maksimum yığın yapısını bozar, bu nedenle bu yöntem uygulanabilir değildir.
Siddhartha

22
BUNU KULLANMA. LinMa ve Siddhartha'nın fark ettiği gibi, push / pop emri bozar.
Alex Fedulov

14
Bir alt çizgi ile başlayan yöntemlerdir özel ve edilebilmektedir önceden haber verilmeksizin kaldırıldı . Onları kullanmayın.
user4815162342

67

Çözüm, değerlerinizi yığın halinde sakladığınızda veya nesne karşılaştırmanızı şöyle tersine çevirmektir:

import heapq

class MaxHeapObj(object):
  def __init__(self, val): self.val = val
  def __lt__(self, other): return self.val > other.val
  def __eq__(self, other): return self.val == other.val
  def __str__(self): return str(self.val)

Maks yığın yığını örneği:

maxh = []
heapq.heappush(maxh, MaxHeapObj(x))
x = maxh[0].val  # fetch max value
x = heapq.heappop(maxh).val  # pop max value

Ancak değerlerinizi sarmayı ve paketini açmayı hatırlamanız gerekir; bu, minimum veya maksimum yığınla uğraştığınızı bilmenizi gerektirir.

MinHeap, MaxHeap sınıfları

MinHeapVe MaxHeapnesneleri için sınıflar eklemek kodunuzu basitleştirebilir:

class MinHeap(object):
  def __init__(self): self.h = []
  def heappush(self, x): heapq.heappush(self.h, x)
  def heappop(self): return heapq.heappop(self.h)
  def __getitem__(self, i): return self.h[i]
  def __len__(self): return len(self.h)

class MaxHeap(MinHeap):
  def heappush(self, x): heapq.heappush(self.h, MaxHeapObj(x))
  def heappop(self): return heapq.heappop(self.h).val
  def __getitem__(self, i): return self.h[i].val

Örnek kullanım:

minh = MinHeap()
maxh = MaxHeap()
# add some values
minh.heappush(12)
maxh.heappush(12)
minh.heappush(4)
maxh.heappush(4)
# fetch "top" values
print(minh[0], maxh[0])  # "4 12"
# fetch and remove "top" values
print(minh.heappop(), maxh.heappop())  # "4 12"

Güzel. Bunu aldım ve list__init__'ye isteğe bağlı bir parametre ekledim , bu durumda çağırıyorum heapq.heapifyve ayrıca bir heapreplaceyöntem ekledim .
Booboo

1
Kimsenin bu yazım tipini yakalamamasına şaşırdım: MaxHeapInt -> MaxHeapObj. Aksi takdirde, gerçekten çok temiz bir çözüm.
Chiraz BenAbdelkader

@ChirazBenAbdelkader düzeltildi, teşekkür ederim.
Isaac Turner

İlginçtir Fanchen Bao'nun bu soruya cevabı çok benzer: stackoverflow.com/questions/8875706/…
Chiraz BenAbdelkader

40

En kolay ve ideal çözüm

Değerleri -1 ile çarpın

İşte böyle. Tüm en yüksek sayılar artık en düşük ve tam tersi.

Bir öğeyi açtığınızda orijinal değeri tekrar almak için -1 ile çarptığınızda unutmayın.


1
Harika, ancak çoğu çözüm sınıfları / diğer türleri destekler ve gerçek verileri değiştirmez. Açık soru, değerin -1 ile çarpılmasının bunları değiştirmeyip değiştirmeyeceğidir (son derece hassas şamandıra).
Alex Baranowski

1
@AlexBaranowski. Bu doğru, ancak destekçinin
Flair

İyi bakım görevlilerinin bazı işlevleri uygulama hakkı vardır, ancak bu IMO aslında kullanışlıdır.
Alex Baranowski

7

Ben heapq bir max yığın sürümünü uyguladı ve PyPI için gönderdi. (Heapq modülü CPython kodunda çok küçük bir değişiklik.)

https://pypi.python.org/pypi/heapq_max/

https://github.com/he-zhe/heapq_max

Kurulum

pip install heapq_max

kullanım

tl; dr: tüm işlevlere '_max' eklemek dışında heapq modülü ile aynı.

heap_max = []                           # creates an empty heap
heappush_max(heap_max, item)            # pushes a new item on the heap
item = heappop_max(heap_max)            # pops the largest item from the heap
item = heap_max[0]                      # largest item on the heap without popping it
heapify_max(x)                          # transforms list into a heap, in-place, in linear time
item = heapreplace_max(heap_max, item)  # pops and returns largest item, and
                                    # adds new item; the heap size is unchanged

4

Karşılaştırılabilir ancak int benzeri olmayan anahtarlar ekliyorsanız, üzerlerinde karşılaştırma işleçlerini geçersiz kılabilirsiniz (yani <= olur> ve> <= olur). Aksi takdirde, heapq modülünde heapq._siftup değerini geçersiz kılabilirsiniz (hepsi sonunda sadece Python kodu).


9
“Hepsi sadece Python kodu”: Python sürümünüze ve kurulumunuza bağlıdır. Örneğin, yüklediğim heapq.py, satırın 309 ( # If available, use C implementation) sonrasında yorumun tam olarak ne yaptığını yapan bir kod içeriyor .
tzot

3

İsteğe bağlı olarak en büyük veya en küçük öğeleri seçmenize izin verme

import heapq
heap = [23, 7, -4, 18, 23, 42, 37, 2, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
heapq.heapify(heap)
print(heapq.nlargest(3, heap))  # [42, 42, 37]
print(heapq.nsmallest(3, heap)) # [-4, -4, 2]

3
Bir açıklama yapılabilir.
Peter Mortensen

Başlığım benim açıklama
jasonleonhard

1
Cevabım sorudan daha uzun. Ne açıklama eklemek istersiniz?
jasonleonhard


2
Bu doğru sonucu verir, ancak aslında verimli hale getirmek için bir yığın kullanmaz. Doküman, her seferinde listenin en büyük ve en küçük olarak sıralanacağını belirtir.
RossFabricant

3

İnt sınıfını genişletmek ve __lt__'yi geçersiz kılmak yollardan biridir.

import queue
class MyInt(int):
    def __lt__(self, other):
        return self > other

def main():
    q = queue.PriorityQueue()
    q.put(MyInt(10))
    q.put(MyInt(5))
    q.put(MyInt(1))
    while not q.empty():
        print (q.get())


if __name__ == "__main__":
    main()

Mümkün, ama işleri çok yavaşlatacak ve fazladan bellek kullanacak gibi hissediyorum. MyInt yığın yapısı dışında da kullanılamaz. Ama bir örnek yazdığınız için teşekkür ederim, görmek ilginç.
Leo Ufimtsev

Hah! Yorum yaptıktan bir gün sonra, özel bir nesneyi bir öbeğe koymam ve bir maksimum öbeğe ihtiyaç duyduğum duruma koştum. Aslında bu gönderiyi yeniden araştırdım ve cevabını buldum ve çözümümü buna dayandırdım. (X bir noktası olan özel bir amacı, y koordinatı ve lt merkezi mesafe karşılaştırarak geçersiz). Bunu yayınladığınız için teşekkür ederim.
Leo Ufimtsev

1

Maksimum yığın oluşturmak için değerleri tersine çeviren bir yığın sarıcı yanı sıra kitaplığı daha OOP benzeri yapmak için bir min-yığın için bir sarıcı sınıfı oluşturduk. İşte özü. Üç sınıf vardır; Heap (soyut sınıf), HeapMin ve HeapMax.

Yöntem:

isempty() -> bool; obvious
getroot() -> int; returns min/max
push() -> None; equivalent to heapq.heappush
pop() -> int; equivalent to heapq.heappop
view_min()/view_max() -> int; alias for getroot()
pushpop() -> int; equivalent to heapq.pushpop

0

Maksimum yığın kullanarak en büyük K öğesini elde etmek istiyorsanız, aşağıdaki numarayı yapabilirsiniz:

nums= [3,2,1,5,6,4]
k = 2  #k being the kth largest element you want to get
heapq.heapify(nums) 
temp = heapq.nlargest(k, nums)
return temp[-1]

1
Ne yazık ki, bunun için zaman karmaşıklığı O (MlogM) 'dir, burada M = len (nums), yığının amacını bozar. nlargestBurada uygulama ve yorumlara bakın -> github.com/python/cpython/blob/…
Arthur S

1
Bilgilendirici yorumunuz için teşekkür ederiz, ekli bağlantıyı kontrol ettiğinizden emin olun.
RowanX

0

Isaac Turner'ın mükemmel cevabını takiben , max yığın kullanarak K Orijinine En Yakın Noktalara dayanan bir örnek vermek istiyorum .

from math import sqrt
import heapq


class MaxHeapObj(object):
    def __init__(self, val):
        self.val = val.distance
        self.coordinates = val.coordinates

    def __lt__(self, other):
        return self.val > other.val

    def __eq__(self, other):
        return self.val == other.val

    def __str__(self):
        return str(self.val)


class MinHeap(object):
    def __init__(self):
        self.h = []

    def heappush(self, x):
        heapq.heappush(self.h, x)

    def heappop(self):
        return heapq.heappop(self.h)

    def __getitem__(self, i):
        return self.h[i]

    def __len__(self):
        return len(self.h)


class MaxHeap(MinHeap):
    def heappush(self, x):
        heapq.heappush(self.h, MaxHeapObj(x))

    def heappop(self):
        return heapq.heappop(self.h).val

    def peek(self):
        return heapq.nsmallest(1, self.h)[0].val

    def __getitem__(self, i):
        return self.h[i].val


class Point():
    def __init__(self, x, y):
        self.distance = round(sqrt(x**2 + y**2), 3)
        self.coordinates = (x, y)


def find_k_closest(points, k):
    res = [Point(x, y) for (x, y) in points]
    maxh = MaxHeap()

    for i in range(k):
        maxh.heappush(res[i])

    for p in res[k:]:
        if p.distance < maxh.peek():
            maxh.heappop()
            maxh.heappush(p)

    res = [str(x.coordinates) for x in maxh.h]
    print(f"{k} closest points from origin : {', '.join(res)}")


points = [(10, 8), (-2, 4), (0, -2), (-1, 0), (3, 5), (-2, 3), (3, 2), (0, 1)]
find_k_closest(points, 3)

0

Https://stackoverflow.com/a/59311063/1328979 üzerinde ayrıntılı olarak açıklamak için, genel durum için tam olarak belgelenmiş, açıklamalı ve test edilmiş bir Python 3 uygulaması.

from __future__ import annotations  # To allow "MinHeap.push -> MinHeap:"
from typing import Generic, List, Optional, TypeVar
from heapq import heapify, heappop, heappush, heapreplace


T = TypeVar('T')


class MinHeap(Generic[T]):
    '''
    MinHeap provides a nicer API around heapq's functionality.
    As it is a minimum heap, the first element of the heap is always the
    smallest.
    >>> h = MinHeap([3, 1, 4, 2])
    >>> h[0]
    1
    >>> h.peek()
    1
    >>> h.push(5)  # N.B.: the array isn't always fully sorted.
    [1, 2, 4, 3, 5]
    >>> h.pop()
    1
    >>> h.pop()
    2
    >>> h.pop()
    3
    >>> h.push(3).push(2)
    [2, 3, 4, 5]
    >>> h.replace(1)
    2
    >>> h
    [1, 3, 4, 5]
    '''
    def __init__(self, array: Optional[List[T]] = None):
        if array is None:
            array = []
        heapify(array)
        self.h = array
    def push(self, x: T) -> MinHeap:
        heappush(self.h, x)
        return self  # To allow chaining operations.
    def peek(self) -> T:
        return self.h[0]
    def pop(self) -> T:
        return heappop(self.h)
    def replace(self, x: T) -> T:
        return heapreplace(self.h, x)
    def __getitem__(self, i) -> T:
        return self.h[i]
    def __len__(self) -> int:
        return len(self.h)
    def __str__(self) -> str:
        return str(self.h)
    def __repr__(self) -> str:
        return str(self.h)


class Reverse(Generic[T]):
    '''
    Wrap around the provided object, reversing the comparison operators.
    >>> 1 < 2
    True
    >>> Reverse(1) < Reverse(2)
    False
    >>> Reverse(2) < Reverse(1)
    True
    >>> Reverse(1) <= Reverse(2)
    False
    >>> Reverse(2) <= Reverse(1)
    True
    >>> Reverse(2) <= Reverse(2)
    True
    >>> Reverse(1) == Reverse(1)
    True
    >>> Reverse(2) > Reverse(1)
    False
    >>> Reverse(1) > Reverse(2)
    True
    >>> Reverse(2) >= Reverse(1)
    False
    >>> Reverse(1) >= Reverse(2)
    True
    >>> Reverse(1)
    1
    '''
    def __init__(self, x: T) -> None:
        self.x = x
    def __lt__(self, other: Reverse) -> bool:
        return other.x.__lt__(self.x)
    def __le__(self, other: Reverse) -> bool:
        return other.x.__le__(self.x)
    def __eq__(self, other) -> bool:
        return self.x == other.x
    def __ne__(self, other: Reverse) -> bool:
        return other.x.__ne__(self.x)
    def __ge__(self, other: Reverse) -> bool:
        return other.x.__ge__(self.x)
    def __gt__(self, other: Reverse) -> bool:
        return other.x.__gt__(self.x)
    def __str__(self):
        return str(self.x)
    def __repr__(self):
        return str(self.x)


class MaxHeap(MinHeap):
    '''
    MaxHeap provides an implement of a maximum-heap, as heapq does not provide
    it. As it is a maximum heap, the first element of the heap is always the
    largest. It achieves this by wrapping around elements with Reverse,
    which reverses the comparison operations used by heapq.
    >>> h = MaxHeap([3, 1, 4, 2])
    >>> h[0]
    4
    >>> h.peek()
    4
    >>> h.push(5)  # N.B.: the array isn't always fully sorted.
    [5, 4, 3, 1, 2]
    >>> h.pop()
    5
    >>> h.pop()
    4
    >>> h.pop()
    3
    >>> h.pop()
    2
    >>> h.push(3).push(2).push(4)
    [4, 3, 2, 1]
    >>> h.replace(1)
    4
    >>> h
    [3, 1, 2, 1]
    '''
    def __init__(self, array: Optional[List[T]] = None):
        if array is not None:
            array = [Reverse(x) for x in array]  # Wrap with Reverse.
        super().__init__(array)
    def push(self, x: T) -> MaxHeap:
        super().push(Reverse(x))
        return self
    def peek(self) -> T:
        return super().peek().x
    def pop(self) -> T:
        return super().pop().x
    def replace(self, x: T) -> T:
        return super().replace(Reverse(x)).x


if __name__ == '__main__':
    import doctest
    doctest.testmod()

https://gist.github.com/marccarre/577a55850998da02af3d4b7b98152cf4


0

Bu basit bir MaxHeapuygulamadır heapq. Rağmen sadece sayısal değerlerle çalışır.

import heapq
from typing import List


class MaxHeap:
    def __init__(self):
        self.data = []

    def top(self):
        return -self.data[0]

    def push(self, val):
        heapq.heappush(self.data, -val)

    def pop(self):
        return -heapq.heappop(self.data)

Kullanımı:

max_heap = MaxHeap()
max_heap.push(3)
max_heap.push(5)
max_heap.push(1)
print(max_heap.top())  # 5
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.