heapq
a[k] <= a[2k+1] and a[k] <= a[2k+2],(k从0开始),则这个列表是小顶堆(不存在的元素被视为无限大)
heapq库是python自带的最小堆实现
常用方法:
- heapq.heappush(heap,item)
当插入一个元素时,该方法会自动调堆中元素的位置。
- 比如插入一个比堆顶还小的元素,则新加入的节点会依次向父节点进行比较,然后调整位置直到堆顶。
- 需要注意的是,这个方法不会调整其他节点的元素位置(即不能调整其他节点满足父节点的值大于孩子节点的值),如下图
上图可以看出,该方法只是对新加入节点到堆顶路径的元素进行了操作。
2.heapq.heappop(heap)
弹出并返回堆中的最小值,保持堆不变。如果堆是空的,会引起IndexError异常。如果想获得最小值而不是弹出它,则使用heap[0]
-
heapq.heappushpop(heap, item)
先压item入堆,然后弹出堆里最小的元素。
这个组合比先 heappush(heap,item) 然后再heappop(heap) 效率高。 -
heapq.heapify(x)
把列表x转换成一个堆,就地转换,只用线性时间 -
heapq.heapreplace(heap,item)
先弹出堆里的最小值,然后压入item。
(其实更推荐用heappushpop(heap,item),因为这样才能保证返回值是最小的) -
一个典型的堆排序可以这样做
>>> def heapsort(iterable):
... h = []
... for value in iterable:
... heappush(h, value)
... return [heappop(h) for i in range(len(h))]
...
>>> heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8, 0])
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
堆排序可以用于任务优先级排序
>>> h = []
>>> heappush(h, (5, 'write code'))
>>> heappush(h, (7, 'release product'))
>>> heappush(h, (1, 'write spec'))
>>> heappush(h, (3, 'create tests'))
>>> heappop(h)
(1, 'write spec')
可是,如果有两个以上事件优先级相同呢?这时该怎么办呢?
可以在优先级后面加一个entry_counts表示进入时的计数值。因为没有两个任务是同时进入的,总有顺序,所以在判断了优先级之后,可以再判断entry_counts以区分相同优先级事件,这样可以让同一优先级下,先加入的任务,先被执行。
bisect
bisect库是python自带的二分查找(边界情况也已经考虑得很好了)
一下是一些方法地操作
- bisect.bisect_left(a, x, lo=0, hi=len(a))
返回应该插入的最左(如果有相同的元素)的下标位置 - bisect.bisect_right(a, x, lo=0, hi=len(a))
等价bisect = bisect_right(bisect.py源码最后两行有明确写)
返回应该插入的最右(如果有相同的元素)的下标位