python内置堆模块

友情链接:heapq 堆

heapq

python内置heapq模块,通过import heapq导入。

heapq模块是用于堆实现优先队列。我们知道队列是先进先出(FIFO),

heapq中的优先队列指的是不论谁先进,最小的先出或者最大的先出

# 需要注意的是heapq的堆是小根堆。
                                 0

                  1                                 2

          3               4                5               6

      7       8       9       10      11      12      13      14

    15 16   17 18   19 20   21 22   23 24   25 26   27 28   29 30
    

# 堆顶位置的元素最小,heapq和python一致,下标索引从0开始。
# heapq提供的主要API, Usage:
heap = []            # creates an empty heap
heappush(heap, item) # pushes a new item on the heap
item = heappop(heap) # pops the smallest item from the heap
item = heap[0]       # smallest item on the heap without popping it
heapify(x)           # transforms list into a heap, in-place, in linear time
item = heapreplace(heap, item) # pops and returns smallest item, and adds
                               # new item; the heap size is unchanged

heapq实现列表排序

基本排序流程

# -*- coding: utf-8 -*-
# created by X. Liu on 2020/3/14

import heapq
import random

li = [i for i in range(10)]
random.shuffle(li)
print('排序前', li)

# step1: 建堆(小根堆)
heapq.heapify(li)
print('小根堆', li)


# step2: 排序
# heapq.heappop()方法弹出堆顶元素,即最小的元素
new_li = []
for i in range(10):
    new_li.append(heapq.heappop(li))

print('排序后', new_li)

# output:
排序前 [3, 4, 9, 0, 5, 1, 6, 2, 8, 7]
小根堆 [0, 2, 1, 3, 5, 9, 6, 4, 8, 7]
排序后 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

堆排序实现版本2 (不考虑时间复杂度)

# 借助 heapq.heappush() & heapq.heappop()
# heappush(h, item)  # Push the value item onto the heap, maintaining the heap invariant.

import heapq

def heap_sort(li):
    h = []
    # 建小根堆
    for i in li:
        heapq.heappush(h, i)
    # 依次弹出最小元素构成有序列表,切片回li
    li[:] = [heapq.heappop() for i in range(len(li))]

对比分析

  • heapq的heapify建堆函数和我们自己实现的建堆函数大同小异。我们自己的sift函数一步到位(实现堆顶元素选位的过程);heapify中使用两步判断比较,其实不如我们自己写的sift好。

  • heappop函数实现每次弹出堆顶元素,弹出后再将整个堆调整为一个新的小根堆。它的目的是为了实现优先队列,所以才会这样设计。我们如果希望借助它实现列表排序,只能手动排序。

补充

heap的值可以是元组

>>> 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')

heapq.heapify(x)底层代码实现

def heapify(x):
    n = len(x)
        for i in reversed(range(n//2)):
            _siftup(x, i)
            
            
def _siftup(heap, pos):
    endpos = len(heap)
    startpos = pos
    newitem = heap[pos]
    # Bubble up the smaller child until hitting a leaf.
    childpos = 2*pos + 1    # leftmost child position
    while childpos < endpos:
        # Set childpos to index of smaller child.
        rightpos = childpos + 1
        if rightpos < endpos and not heap[childpos] < heap[rightpos]:
            childpos = rightpos
        # Move the smaller child up.
        heap[pos] = heap[childpos]
        pos = childpos
        childpos = 2*pos + 1
    # The leaf at pos is empty now.  Put newitem there, and bubble it up
    # to its final resting place (by sifting its parents down).
    heap[pos] = newitem
    _siftdown(heap, startpos, pos)
    
    
def _siftdown(heap, startpos, pos):
    newitem = heap[pos]
    # Follow the path to the root, moving parents down until finding a place
    # newitem fits.
    while pos > startpos:
        parentpos = (pos - 1) >> 1
        parent = heap[parentpos]
        if newitem < parent:
            heap[pos] = parent
            pos = parentpos
            continue
        break
    heap[pos] = newitem

heapq.heappop底层代码实现

def heappop(heap):
    """Pop the smallest item off the heap, maintaining the heap invariant."""
    lastelt = heap.pop()    # raises appropriate IndexError if heap is empty
    if heap:
        returnitem = heap[0]
        heap[0] = lastelt
        _siftup(heap, 0)
        return returnitem
    return lastelt
posted @ 2020-03-14 15:06  the3times  阅读(820)  评论(0编辑  收藏  举报