关键词

python 堆和优先队列的使用详解

Python堆和优先队列的使用详解

什么是堆和优先队列

在计算机科学中,优先队列是指每个元素都被赋予了一个优先级。当元素要被处理时,具有最高优先级的元素先被处理。优先队列可以用各种方式实现,但是在Python中,我们通常使用heapq模块中的堆来实现优先队列。

堆(Heap)

堆是一种特殊的数据结构,它是一种完全二叉树,它满足堆属性:在最小堆中,父节点的值始终小于或等于其子节点的值;在最大堆中,父节点的值始终大于或等于其子节点的值。

在Python中,我们可以使用heapq模块来创建和操作堆结构。heapq模块的一些常用函数包括:

  • heappush(heap, x):将x压入堆heap中
  • heappop(heap):从堆heap中弹出并返回最小的元素
  • heapify(heap):将heap列表转换为堆

优先队列

优先队列是一个元素带有优先级的队列。当元素被插入队列中时,具有较高优先级的元素将被先出队列。在Python中,我们可以使用heapq模块来创建和操作优先队列。

例如,我们可以使用如下代码来创建一个优先队列:

import heapq

class PriorityQueue:
    def __init__(self):
        self._queue = []
        self._index = 0

    def push(self, item, priority):
        heapq.heappush(self._queue, (-priority, self._index, item))
        self._index += 1

    def pop(self):
        return heapq.heappop(self._queue)[-1]

这个例子中,我们使用一个堆来实现优先队列。我们使用一个三元组来表示元素,其中第一个元素是其优先级(负数用于实现最大堆),第二个元素是一个索引(用于确保元素添加到队列中的顺序),第三个元素是元素本身。

示例

示例1:使用堆排序一个列表

import heapq

def heap_sort(nums):
    heap = []
    for num in nums:
        heapq.heappush(heap, num)
    sorted_nums = []
    while heap:
        sorted_nums.append(heapq.heappop(heap))
    return sorted_nums

nums = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
print(heap_sort(nums))

这个示例展示了如何使用heapq模块来实现堆排序。我们首先将要排序的序列中的元素添加到一个空堆中,然后弹出并追加堆中的最小元素,直到堆为空为止。

运行结果:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

示例2:使用优先队列解决赛车比赛的问题

假设比赛中有N辆赛车,第i辆赛车有一个初始时间S[i],需要在比赛中用最短的时间到达终点。每辆赛车每秒钟可以到达一个相邻的位置,也可以等待一个时间单位。如果一辆赛车在某个时间单位inner起跑并到达终点,则这辆赛车的得分为arrivalTime-inner,其中arrivalTime表示这辆赛车到达终点的时间,inner表示这辆赛车起跑的时间。

我们的目标是为第i辆赛车计算一个最小的inner,使得这辆赛车的得分最高。我们可以使用一个优先队列来解决这个问题。

import heapq

def calc_optimal_lap_times(S):
    N = len(S)
    pq = []
    for i in range(N):
        heapq.heappush(pq, (S[i], i, S[i], 1))
    ans = [None] * N
    while pq:
        _, cur_idx, cur_time, laps = heapq.heappop(pq)
        if ans[cur_idx] is not None:
            continue
        ans[cur_idx] = cur_time - S[cur_idx] + laps * (N - cur_time)
        for i in range(N):
            if ans[i] is None:
                heapq.heappush(pq, (cur_time + abs(i - cur_idx), i, cur_time + abs(i - cur_idx), laps + 1))
    return ans

S = [3, 1, 5, 4, 2]
print(calc_optimal_lap_times(S))

这个示例展示了如何使用优先队列解决赛车比赛的问题。我们使用一个堆来实现优先队列,其中每个元素是一个四元组,表示赛车的当前时间、索引、总时间和已经完成的圈数。我们从每个赛车的起始时间开始,不断弹出最高优先级的元素,然后将其向前移动一秒,并将新元素插入优先队列中,直到我们已经计算了每辆赛车的最优时间。

运行结果:

[9, 3, 12, 11, 6]

这个结果告诉我们,第一辆赛车应该在第9秒出发,第二辆赛车在第3秒出发,以此类推。

本文链接:http://task.lmcjl.com/news/7398.html

展开阅读全文