我在Python中使用什么来实现最大堆实现?

Dou*_*yle 197 python heap recursive-datastructures data-structures

Python包含用于min-sheaps的heapq模块,但我需要一个最大堆.我应该在Python中使用什么来实现max-heap实现?

Dan*_*ach 198

最简单的方法是反转键的值并使用heapq.例如,将1000.0转换为-1000.0,将5.0转换为-5.0.

  • 它也是标准解决方案. (33认同)
  • uggh; 总污泥.我很惊讶`heapq`没有提供反向. (31认同)
  • 哇.我很惊讶*这不是由`heapq`提供的,而且没有好的选择. (29认同)
  • @gatoatigrado:如果你有一些不容易映射到`int` /`float`的东西,你可以通过将它们包装在一个带有倒置的`__lt__`运算符的类中来反转排序. (17认同)
  • @Aerovistae同样的建议适用:反转值(即切换符号),无论开始是正还是负. (5认同)
  • 如果你有一个积极和消极的数字混合开始怎么办?那又怎样? (3认同)
  • 是的,如果你没有 `int` / `float`'s 的话,反转就无济于事了……事实上,对于一个订单,一般来说真的不需要任何合理的反转(例如,与自然数同构的东西)。 (2认同)
  • 这很丑,你怎么把`string`反转呢? (2认同)

Lij*_*eph 190

您可以使用

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!!
Run Code Online (Sandbox Code Playgroud)

如果您想要弹出元素,请使用:

heapq.heappop(minheap)      # pop from minheap
heapq._heappop_max(maxheap) # pop from maxheap
Run Code Online (Sandbox Code Playgroud)

  • 哇.我很惊讶*在heapq中有*这样的内置解决方案.但是,在官方文件中,甚至根本没有提及*甚至完全*不合理*!WTF! (102认同)
  • 看起来最大堆有一些未记录的函数:`_heapify_max`,`_heappushpop_max`,`_siftdown_max`和`_siftup_max`. (26认同)
  • 任何pop/push函数都会破坏最大堆结构,因此这种方法不可行. (19认同)
  • 不要使用它.正如LinMa和Siddhartha注意到的那样,推/弹打破了秩序. (15认同)
  • 以下划线开头的方法是“私有”的,可以被删除而无需事先通知**。不要使用它们。 (6认同)
  • 嗨Lijo,看起来像_heapify_max不能用于动态添加/删除元素?请参阅我的代码=> http://stackoverflow.com/questions/33024215/built-in-max-heap-api-in-python,您的见解表示赞赏.谢谢.:) (4认同)
  • 显而易见,`_heapify_max`等是私有函数,因此不属于模块API。就功能和向前兼容性而言,使用风险自负。 (4认同)
  • 不知怎的,我在Python Python 2.7.3中找不到这个. (3认同)
  • 只要不推送新元素并使用`_heappop_max`弹出它们,就可以使用它 (2认同)
  • @oerpli `._heappop_max` 在我的 Python 2.7.15 中不存在,只有 `._heappushpop_max` 和 `._heapify_max` 用于下划线方法。看起来接口在 Python 3 中发生了变化以包含它。 (2认同)
  • 这些私有方法是为了支持“heapq.nsmallest”和“heapq.merge”以及“reverse=True”而构建的。 (2认同)

Isa*_*ner 50

解决方案是在将它们存储在堆中时否定您的值,或者反转您的对象比较,如下所示:

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)
Run Code Online (Sandbox Code Playgroud)

最大堆的示例:

maxh = []
heapq.heappush(maxh,MaxHeapInt(x))
x = maxh[0].val # fetch max value
x = heapq.heappop(maxh).val # pop max value
Run Code Online (Sandbox Code Playgroud)

但是你必须记住包装和解包你的值,这需要知道你是在处理最小或最大堆.

MinHeap,MaxHeap类

MinHeapMaxHeap对象添加类可以简化代码:

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
Run Code Online (Sandbox Code Playgroud)

用法示例:

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"
Run Code Online (Sandbox Code Playgroud)

  • 令人惊讶的是没有人发现这个拼写错误:MaxHeapInt --> MaxHeapObj。否则,确实是一个非常干净的解决方案。 (2认同)

Seb*_*sen 25

将值乘以-1,然后就可以了.现在所有最高的数字都是最低的,反之亦然.

请记住,当您弹出一个元素再次与-1相乘时,为了再次获得原始值.

  • 很好,但大多数解决方案支持类/其他类型,并且不会更改实际数据。悬而未决的问题是,将值乘以 -1 是否不会改变它们(极其精确的浮点数)。 (5认同)
  • @亚历克斯巴拉诺夫斯基。这是真的,但这是维护者的回应:https://bugs.python.org/issue27295 (2认同)

Vik*_*sad 18

我还需要使用最大堆,并且我正在处理整数,所以我只包装了我需要的两个方法,heap如下所示:

import heapq


def heappush(heap, item):
    return heapq.heappush(heap, -item)


def heappop(heap):
    return -heapq.heappop(heap)
Run Code Online (Sandbox Code Playgroud)

然后我只是分别用和替换了我的heapq.heappush()heapq.heappop()电话。heappush()heappop()


Zhe*_* He 11

我实现了 heapq 的最大堆版本并将其提交给 PyPI。(heapq 模块 CPython 代码的细微变化。)

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

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

安装

pip install heapq_max
Run Code Online (Sandbox Code Playgroud)

用法

tl;dr:除了向所有函数添加“_max”外,与 heapq 模块相同。

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
Run Code Online (Sandbox Code Playgroud)


Yuc*_*ong 11

这是一个MaxHeap基于heapq. 虽然它只适用于数值。

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)
Run Code Online (Sandbox Code Playgroud)

用法:

max_heap = MaxHeap()
max_heap.push(3)
max_heap.push(5)
max_heap.push(1)
print(max_heap.top())  # 5
Run Code Online (Sandbox Code Playgroud)

  • 这要求堆元素支持否定,但这不是给定的。 (2认同)

Tha*_*ine 11

最简单的方法 是将每个元素转换为负数,它会解决您的问题。

import heapq
heap = []
heapq.heappush(heap, 1*(-1))
heapq.heappush(heap, 10*(-1))
heapq.heappush(heap, 20*(-1))
print(heap)
Run Code Online (Sandbox Code Playgroud)

输出将如下所示:

[-20, -1, -10]
Run Code Online (Sandbox Code Playgroud)

  • 如果你有零并且需要将其推入 maxHeap 该怎么办?抱歉,只是卡住了 (4认同)

ill*_*ato 7

最简单的方法:

from heapq import *

h = [5, 7, 9, 1, 3]
h_neg = [-i for i in h]
heapify(h_neg)            # heapify
heappush(h_neg, -2)       # push
print(-heappop(h_neg))    # pop
# 9
Run Code Online (Sandbox Code Playgroud)


rlo*_*tun 5

如果您要插入可比较但不是类似 int 的键,您可能会覆盖它们上的比较运算符(即 <= 变为 > 和 > 变为 <=)。否则,您可以覆盖 heapq 模块中的 heapq._siftup (最后,这只是 Python 代码)。

  • “这只是 Python 代码”:这取决于您的 Python 版本和安装。例如,我安装的 heapq.py 在第 309 行(`# If available, use C implementation`)之后有一些代码,它完全符合注释所描述的内容。 (10认同)