📜  在Python中使用 heapq 模块的堆和优先级队列

📅  最后修改于: 2022-05-13 01:54:20.371000             🧑  作者: Mango

在Python中使用 heapq 模块的堆和优先级队列

堆是广泛使用的树状数据结构,其中父节点满足以下任一标准。

  • 每一层中父节点的值都小于或等于其子节点的值——min-heap。
  • 每一层中父节点的值大于或等于其子节点的值——max-heap。

堆是完整的二叉树,用于实现优先级队列。最小堆在调度作业、调度电子邮件或根据优先级为任务分配资源方面发挥着至关重要的作用。

优先队列

这些是抽象数据类型,是一种特殊形式的队列。队列中的元素具有分配给它们的优先级。根据优先级,优先级队列中的第一个元素将是具有最高优先级的元素。下面列出了与这些优先级队列相关的基本操作:

  • is_empty:检查队列是否为空。
  • insert :插入一个元素及其优先级。该元素将仅按其优先级顺序放置。
  • pop :弹出优先级最高的元素。第一个元素将是具有最高优先级的元素。

优先级队列可用于所有调度类型的进程。程序员可以决定是将最大的数字视为最高优先级还是将最小的数字视为最高优先级。如果两个元素具有相同的优先级,则它们按照它们在队列中出现的顺序出现。

Python中的 heapq 模块

Heapq 模块是堆队列算法(优先队列算法)的一个实现,其中保留了最小堆的属性。该模块采用项目列表并重新排列它,使其满足以下最小堆标准:

  • 索引“i”中的父节点小于或等于其子节点。
  • 索引'i'中节点的左子节点位于索引'(2*i) + 1'中。
  • 索引'i'中节点的右孩子在索引'(2*i) + 2'中。

使用 heapq 模块的优先级队列

优先级队列在Python中实现为元组列表,其中元组包含优先级作为第一个元素,值作为下一个元素。

例子:

考虑一个简单的优先级队列实现,用于根据学生的卷号安排学生的演示。这里的卷号决定了学生呈现的优先级。因为它是一个最小堆,所以卷号 1 被认为是最高优先级。

Python3
# import modules
import heapq as hq
  
# list of students
list_stu = [(5,'Rina'),(1,'Anish'),(3,'Moana'),(2,'cathy'),(4,'Lucy')]
  
# Arrange based on the roll number
hq.heapify(list_stu)
  
print("The order of presentation is :")
  
for i in list_stu:
  print(i[0],':',i[1])


Python3
import time
import heapq as hq
  
# jobs to be executed
jobs = [(2, 'task_1'), (5, 'task_2'), (1, 'task_4'),
        (4, 'task_5'), (3, 'task_3'), (1, 'task_8')]
  
# interrupts
interrupts = [(1, 'intr_1'), (2, 'intr_2'), (13, 'intr_3')]
  
i, j = 0, 0
  
# Arranging jobs in heap
hq.heapify(jobs)
  
print(jobs, "\n\n")
  
# scheduling the tasks
while len(jobs) != 0:
  
    # printing execution log
    print("The ", jobs[0][1], " with priority ",
          jobs[0][0], " in progress", end="")
  
    # servicing the tasks
    for _ in range(0, 5):
  
        print(".", end="")
        time.sleep(0.5)
  
    # pop the job that completed
    hq.heappop(jobs)
  
    # adding interrupts
    if j < len(interrupts):
  
        hq.heappush(jobs, interrupts[j])
        print("\n\nNew interrupt arrived!!", interrupts[j])
        print()
        j = j+1
  
    # job queue after arrival of interrupt
    print("\n Job queue currently :", jobs)
    print("\n")
  
  
print("\nAll interrupts and jobs completed!")


输出
The order of presentation is :
1 : Anish
2 : cathy
3 : Moana
5 : Rina
4 : Lucy

示例 2:

现在让我们实现一个简单的调度程序,将作业分配给处理器。调度程序使用优先级队列来决定必须执行哪个任务。除了任务之外,还有接近调度器的中断。所以调度器必须决定是执行中断还是执行现有任务。如果中断的优先级更高,则先执行,否则,一旦所有作业完成,将服务中断。为了实现这一点,使用了 heapq 模块。方法如下。

  • 要执行的任务具有优先级。优先级为“1”的元素被认为是最重要的任务。
  • 所有任务都在一个优先级队列中,并使用 min-heap 属性进行维护。
  • 任务得到服务,并且在进行中时,只会打印一条消息作为执行日志,说明哪个任务正在进行中。
  • 中断及其优先级接近调度程序。
  • 中断被推送到保留最小堆属性的优先级队列中。
  • 具有最高优先级的任务/中断将首先得到服务,并且它始终是队列中的第一个元素。
  • 一旦 task.interrupt 被服务,它就会从堆队列中弹出。

蟒蛇3

import time
import heapq as hq
  
# jobs to be executed
jobs = [(2, 'task_1'), (5, 'task_2'), (1, 'task_4'),
        (4, 'task_5'), (3, 'task_3'), (1, 'task_8')]
  
# interrupts
interrupts = [(1, 'intr_1'), (2, 'intr_2'), (13, 'intr_3')]
  
i, j = 0, 0
  
# Arranging jobs in heap
hq.heapify(jobs)
  
print(jobs, "\n\n")
  
# scheduling the tasks
while len(jobs) != 0:
  
    # printing execution log
    print("The ", jobs[0][1], " with priority ",
          jobs[0][0], " in progress", end="")
  
    # servicing the tasks
    for _ in range(0, 5):
  
        print(".", end="")
        time.sleep(0.5)
  
    # pop the job that completed
    hq.heappop(jobs)
  
    # adding interrupts
    if j < len(interrupts):
  
        hq.heappush(jobs, interrupts[j])
        print("\n\nNew interrupt arrived!!", interrupts[j])
        print()
        j = j+1
  
    # job queue after arrival of interrupt
    print("\n Job queue currently :", jobs)
    print("\n")
  
  
print("\nAll interrupts and jobs completed!")

输出