【Python练习cookbook】heapq高级应用

heapq官方文档:https://docs.python.org/zh-cn/3/library/heapq.html#module-heapq

1.从集合中取出最大或最小N个元素

import heapq
nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
print(heapq.nlargest(3, nums)) # 输出 [42, 37, 23]
print(heapq.nsmallest(3, nums)) # 输出 [-4, 1, 2]

也支持其他参数支持更为复杂的数据结构

portfolio = [
    {'name': 'IBM', 'shares': 100, 'price': 91.1},
    {'name': 'AAPL', 'shares': 50, 'price': 543.22},
    {'name': 'FB', 'shares': 200, 'price': 21.09},
    {'name': 'HPQ', 'shares': 35, 'price': 31.75},
    {'name': 'YHOO', 'shares': 45, 'price': 16.35},
    {'name': 'ACME', 'shares': 75, 'price': 115.65}
]
cheap = heapq.nsmallest(3, portfolio, key=lambda s: s['price'])
expensive = heapq.nlargest(3, portfolio, key=lambda s: s['price'])

nlargest和nsmallest实现时先调用了heapify

 如果N与对象数量相差较大,则用nlargest和nsmaalest效率才高,否则先sorted再切片即可:

sorted(items)[:N] 
sorted(items)[-N:]

其实,当取出的N>size时,nlargest和nsmallest的实现就是用的sorted. 

                                                                                                                                                                                                       

补充heapq的其他常见函数说明:(引自:https://blog.csdn.net/brucewong0516/article/details/79042839

数据结构堆(heap)是一种优先队列。使用优先队列能够以任意顺序增加对象,并且能在任意的时间(可能在增加对象的同时)找到(也可能移除)最小的元素,也就是说它比python的min方法更加有效率。

1、heappush(heap,n)数据堆入

In [1]: import heapq as hq
In [2]: import numpy as np
In [3]: data = np.arange(10)
#将生成的数据随机打乱顺序
In [4]: np.random.shuffle(data)
In [5]: data
Out[5]: array([5, 8, 6, 3, 4, 7, 0, 1, 2, 9])
#定义heap列表
In [6]: heap = []
#使用heapq库的heappush函数将数据堆入
In [7]: for i in data:
   ...:     hq.heappush(heap,i)
   ...:
In [8]: heap
Out[8]: [0, 1, 3, 2, 5, 7, 6, 8, 4, 9]

In [9]: hq.heappush(heap,0.5)
In [10]: heap
Out[10]: [0, 0.5, 3, 2, 1, 7, 6, 8, 4, 9, 5]

2、heappop(heap)将数组堆中的最小元素弹出

In [11]: hq.heappop(heap)
Out[11]: 0

In [12]: hq.heappop(heap)
Out[12]: 0.5

3、heapify(heap) 将heap属性强制应用到任意一个列表

heapify 函数将使用任意列表作为参数,并且尽可能少的移位操作,,将其转化为合法的堆。如果没有建立堆,那么在使用heappush、heappop、heapreplace前应该使用该函数。

In [13]: heap = [5,8,0,3,6,7,9,1,4,2]

In [14]: hq.heapify(heap)

In [15]: heap
Out[15]: [0, 1, 5, 3, 2, 7, 9, 8, 4, 6]

heap = [5,8,0,3,6,7,9,1,4,2]
hq.heappop(heap)
Out[70]: 5
heap = [5,8,0,3,6,7,9,1,4,2]
hq.heapify(heap)
hq.heappop(heap)
Out[73]: 0
heap = [5,8,0,3,6,7,9,1,4,2]
hq.heapreplace(heap,10)
Out[75]: 5
heap = [5,8,0,3,6,7,9,1,4,2]
hq.heapify(heap)
hq.heapreplace(heap,10)
Out[78]: 0



4、heapreplace(heap,n)弹出最小的元素被n替代

In [17]: hq.heapreplace(heap,0.5)
Out[17]: 0

In [18]: heap
Out[18]: [0.5, 1, 5, 3, 2, 7, 9, 8, 4, 6]

5、nlargest(n,iter)、nsmallest(n,iter)
heapq中剩下的两个函数nlargest(n.iter)和nsmallest(n.iter)分别用来寻找任何可迭代的对象iter中第n大或者第n小的元素。可以通过使用排序(sorted函数)和分片进行完成。

#返回第一个最大的数
In [19]: hq.nlargest(1,heap)
Out[19]: [9]
#返回第一个最小的数
In [20]: hq.nsmallest(1,heap)
Out[20]: [0.5]
————————————————
版权声明:本文为CSDN博主「brucewong0516」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/brucewong0516/article/details/79042839

                                                                                                                                                                                                       

2.实现一个队列,该队列按给定的优先级对元素进行排序,并使pop操作始终返回每个优先级最高的元素

import heapq

class PriorityQueue:
    def __init__(self):
        self._queue = []
        self._index = 0

def push(self, item, priority):
    heapq.heappush(self._queue, (-priority, self._index, item))
    self._index += 1

def pop(self):
    return heapq.heappop(self._queue)[-1]

heapq.heappush(queue,item)会按item1

其中,优先级前加负号可让堆有优先级从高到低排序。index用于处理优先级一样的元素。

index的另一个作用是避免优先级和index一样时(因为index不可能相同),比较item:

>>> a = (1, Item('foo'))
>>> b = (5, Item('bar'))
>>> a < b
True
>>> c = (1, Item('grok'))
>>> a < c
Traceback (most recent call last):
File "", line 1, in
TypeError: unorderable types: Item() < Item()

因为我们并未定义Item的比较操作,所以会报如上错误

应用实例:

>>> class Item:
...     def __init__(self, name):
...        self.name = name
...    def __repr__(self):
...         return 'Item({!r})'.format(self.name)
...
>>> q = PriorityQueue()
>>> q.push(Item('foo'), 1)
>>> q.push(Item('bar'), 5)
>>> q.push(Item('spam'), 4)
>>> q.push(Item('grok'), 1)
>>> q.pop()
Item('bar')
>>> q.pop()
Item('spam')
>>> q.pop()
Item('foo')
>>> q.pop()
Item('grok')

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值