天天看點

python之堆heapq子產品python之堆heapq子產品

python之堆heapq子產品

堆是一種特殊的樹形結構,通常我們所說的堆的資料結構指的是完全二叉樹,并且根節點的值小于等于該節點所有子節點的值。

python之堆heapq子產品python之堆heapq子產品

堆是非線性的樹形的資料結構,有兩種堆,最大堆與最小堆。( heapq庫中的堆預設是最小堆)

  • 最大堆,樹種各個父節點的值總是大于或等于任何一個子節點的值。
  • 最小堆,樹種各個父節點的值總是小于或等于任何一個子節點的值。

我們一般使用二叉堆來實作優先級隊列,它的内部調整算法複雜度為logN。

堆是一個二叉樹,其中最小堆每個父節點的值都小于或等于其所有子節點的值。

整個最小堆的最小元素總是位于二叉樹的根節點。

常用方法

heappush(heap,item) 往堆中插入一條新的值
heappop(heap) 從堆中彈出最小值
heapreplace(heap,item) 從堆中彈出最小值,并往堆中插入item   【注意:與heappushpop(heap,item)的差別在于,順序不同,這裡是先進行删除,後壓入堆】
heappushpop(heap,item) Python3中的heappushpop更進階  【注意:相當于先操作了heappush(heap,item),然後操作heappop(heap)】
heapify(x) 以線性時間将一個清單轉化為堆  【直接會對清單進行排序變成堆排序】
merge(*iterables,key=None,reverse=False) 合并對個堆,然後輸出
nlargest(n,iterable,key=None) 傳回可枚舉對象中的n個最大值并傳回一個結果集list
nsmallest(n,iterable,key=None) 傳回可枚舉對象中的n個最小值并傳回一個結果集list

常用方法示例:

import heapq
import random


def test():
    li = list(random.sample(range(100), 6))
    print(li)

    n = len(li)
    # nlargest
    print("nlargest:", heapq.nlargest(n, li))
    # nsmallest
    print("nsmallest:", heapq.nsmallest(n, li))
    # heapify
    print('original list is', li)
    heapq.heapify(li)
    print('heapify  list is', li)
    # heappush & heappop  
    heapq.heappush(li, 105)
    print('pushed heap is', li)
    heapq.heappop(li)
    print('popped heap is', li)
    # heappushpop & heapreplace  
    heapq.heappushpop(li, 130)  # heappush -> heappop
    print('heappushpop', li)
    heapq.heapreplace(li, 2)  # heappop -> heappush
    print('heapreplace', li)


test()
           

運作結果:

python之堆heapq子產品python之堆heapq子產品

堆排序示例 

heapq子產品中有幾張方法進行排序:

方法一:

import heapq


def heap_sort(iterable):
    heap = []
    for i in iterable:
        heapq.heappush(heap, i)

    return [heapq.heappop(heap) for _ in range(len(heap))]


if __name__ == '__main__':
    li = [30, 40, 60, 10, 20, 50]
    print(heap_sort(li))
           

運作結果:

python之堆heapq子產品python之堆heapq子產品

方法二(使用nlargest或nsmallest):

import heapq

li = [30, 40, 60, 10, 20, 50]
# nlargest
n = len(li)
print("nlargest:", heapq.nlargest(n, li))
# nsmallest
print("nsmallest:", heapq.nsmallest(n, li))
           

運作結果:

python之堆heapq子產品python之堆heapq子產品

方法三(使用heapify):

import heapq


def heap_sort(list):
    print(list)
    heapq.heapify(list)
    print(list)
    heap = []

    while (list):
        heap.append(heapq.heappop(list))

    print(heap)
    li[:] = heap
    print(li)


if __name__ == '__main__':
    li = [30, 40, 60, 10, 20, 50]
    heap_sort(li)
           

運作結果:

python之堆heapq子產品python之堆heapq子產品

堆在優先級隊列中的應用

  需求:實作任務的添加,删除(相當于任務的執行),修改任務優先級

from heapq import *
import itertools

pq = []  # list of entries arranged in a heap
entry_finder = {}  # mapping of tasks to entries
REMOVED = '<removed-task>'  # placeholder for a removed task
counter = itertools.count()  # unique sequence count


def add_task(task, priority=0):
    'Add a new task or update the priority of an existing task'
    if task in entry_finder:
        remove_task(task)
    count = next(counter)
    entry = [priority, count, task]
    entry_finder[task] = entry
    heappush(pq, entry)


def remove_task(task):
    'Mark an existing task as REMOVED.  Raise KeyError if not found.'
    entry = entry_finder.pop(task)
    entry[-1] = REMOVED


def pop_task():
    'Remove and return the lowest priority task. Raise KeyError if empty.'
    while pq:
        priority, count, task = heappop(pq)
        if task is not REMOVED:
            del entry_finder[task]
            return task
    raise KeyError('pop from an empty priority queue')