维护固定大小的堆-python

bnl4lu3b  于 2023-08-02  发布在  Python
关注(0)|答案(7)|浏览(129)
h = []
heapq.heappush(h,(10, 1200))
heapq.heappush(h,(20, 31))
heapq.heappush(h,(5, 1))

字符串
我想保持一个固定的堆大小,比如说3,所以当我下一次有heapq.heappush(h,(3,15))时,值为20的键被删除,剩下的值是3,5和10。

mnemlml8

mnemlml81#

heapq中没有内置的方法来检查大小,所以你必须自己做:

if len(h) < capacity:
    heapq.heappush(h, thing)
else:
    # Equivalent to a push, then a pop, but faster
    spilled_value = heapq.heappushpop(h, thing)
    do_whatever_with(spilled_value)

字符串
另外,请注意,heapq实现的是最小堆,而不是最大堆。你需要颠倒你的优先顺序,可能是否定它们。

o8x7eapl

o8x7eapl2#

我发现这篇文章,我试图实现一个固定大小的top-n堆,这里是我可以提供的解决方案:

from heapq import heapify, heappush, heappushpop, nlargest

class MaxHeap():
    def __init__(self, top_n):
        self.h = []
        self.length = top_n
        heapify( self.h)
        
    def add(self, element):
        if len(self.h) < self.length:
            heappush(self.h, element)
        else:
            heappushpop(self.h, element)
            
    def getTop(self):
        return sorted(self.h, reverse=True)

字符串
(感谢@CyanoKobalamyne)

from heapq import heapify, heappush, heappushpop, nlargest

class MaxHeap():
    def __init__(self, top_n):
        self.h = []
        self.length = top_n
        heapify( self.h)
        
    def add(self, element):
        if len(self.h) < self.length:
            heappush(self.h, element)
        else:
            heappushpop(self.h, element)
            
    def getTop(self):
        return nlargest(self.length, self.h)

wfsdck30

wfsdck303#

如果你想要 k 个最小的元素,这相当于在每次推送时丢弃一个固定大小的最小堆中的最大元素,你应该在你正在构建堆的可迭代对象上使用heapq.nsmallest(或相反的heapq.nlargest)。

ha5z0ras

ha5z0ras4#

Python(目前是3.8x版)没有内置的固定堆大小功能。你有两个选择:
1.维护一个堆,并在每次推送时检查size > fixedSize是否弹出。这意味着在任何给定的时间,堆的最大大小可能是fixedSize+1,这是你将弹出一个的时候。
1.另一种选择是使用heapq.heapreplace(heap, item),根据文档:
从堆中弹出并返回最小的项,并推送新项。堆大小不会改变。如果堆为空,则引发IndexError。这个一步操作比heappop()和heappush()更有效,并且在使用固定大小的堆时更合适。

66bbxpm5

66bbxpm55#

我自己也需要这样的东西,一个有最大长度的项目排序列表。
我使用了双端队列,因为它的“maxlen”属性。

import collections
import bisect

h = collections.deque(maxlen=3)

def insert(h, item):
    if len(h) < h.maxlen or item < h[-1]:
        if len(h) == h.maxlen:
            h.pop()
        bisect.insort_left(h, item)

>>> insert(h, 200); print(h)
deque([200], maxlen=3)

>>> insert(h, 100); print(h)
deque([100, 200], maxlen=3)

>>> insert(h, 200); print(h)
deque([100, 200, 200], maxlen=3)

>>> insert(h, 150); print(h)
deque([100, 150, 200], maxlen=3)

>>> insert(h, 200); print(h)
deque([100, 150, 200], maxlen=3)

>>> insert(h, 1); print(h)
deque([1, 100, 150], maxlen=3)

>>> insert(h, 100); print(h)
deque([1, 100, 100], maxlen=3)

>>> insert(h, 20); print(h)
deque([1, 20, 100], maxlen=3)

字符串

1mrurvl1

1mrurvl16#

要实现有限大小的堆,您可以在每次推送操作后截断堆。

limited_sized_heap = limited_sized_heap[:max_size_of_heap]

字符串
这里有一个例子。

import random
import heapq

max_size_of_heap = 5
limited_sized_heap = []    

for i in range(10):
   a_random = random.randint(1,9)
   heapq.heappush( limited_sized_heap, a_random )
   limited_sized_heap = limited_sized_heap[:max_size_of_heap]
   print(limited_sized_heap)


产出:

[3]
[3, 9]
[3, 9, 4]
[3, 4, 4, 9]
[2, 3, 4, 9, 4]
[1, 3, 2, 9, 4]
[1, 3, 1, 9, 4]
[1, 3, 1, 9, 4]
[1, 3, 1, 9, 4]
[1, 3, 1, 9, 4]


如果你需要绝对固定大小的堆,而不是有限大小的堆,你可以只使用具有无限值的固定大小的列表来初始化堆。

fixed_sized_heap = [float('inf')] * heap_size

fwzugrvs

fwzugrvs7#

heapq中没有内置的函数来检查大小,所以你必须自己做:

if len(h) < capacity:
    heapq.heappush(h, thing)
else:
    # pushes the element on and then pops off the top
    heapq.heappushpop(h, thing)

字符串
请注意,heapq实现了一个最小堆,而不是最大堆。你需要颠倒你的优先顺序
我看到你在你的帖子中特别提到你想要一个固定大小为3的最大堆,并且在添加新元素时能够保持最小的元素。
通过在插入min堆时对元素取反,您将能够利用堆弹出。您现在将删除最大的元素并替换它,而不是删除最小的元素并替换它
这样做的缺点是,当你弹出元素时,你会看到它们的大小顺序是相反的。所以如果你想要一个正确的升序列表,你就必须否定它们并颠倒它们的顺序
下面是一个例子:
A visualization of pushpop when using the default minheap vs when negating the elements of the minheap
Here's an example of how it's implemented in a specific problem with the same requirements outlined in your post

相关问题