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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM