【队列】——PriorityQueue优先队列

队列

队列的特点大家都知道,是先进先出(FIFO),就和排队一样。

在这里插入图片描述

二叉堆

二叉堆是一种特殊的堆,其主要应用有两个,首先是一种排序方法——堆排序,第二是优先级队列

二叉堆有两种:最大堆和最小堆。

  • 最大堆:最大堆的堆顶是整个堆中的最大元素,父结点的键值总是大于或等于任何一个子节点的键值;
  • 最小堆:最小堆的堆顶是整个堆中的最小元素,父结点的键值总是小于或等于任何一个子节点的键值。

二叉堆其实就是一种特殊的二叉树(完全二叉树,节点一层一层,从左到右按顺序排列),只不过存储在数组里。一般的链表二叉树,我们操作节点的指针,而在数组里,我们把数组索引作为指针。

我们在表示一个堆(大顶堆或小顶堆)的时候,实际上是通过一个一维数组来维护一个D叉树(d-ary heap),首先看下图的二叉树(d=2,d表示每个父节点最多有几个子节点),数字代表索引:

  • 任意一个节点的父节点的索引为:(index - 1) / d
  • 任意一个节点的左子节点的索引为:(index * d) + 1
  • 任意一个节点的右子节点的索引为:(index * d) + 2

它的时间复杂度为O(logn·dn)。

二叉堆的主要操作就两个,sink(下沉)和swim(上浮)。

以大顶堆为例

swim(上浮)

如果某个节点 A 比它的父节点大,那么 A 不应该做子节点,应该把父节点换下来,自己去做父节点,这就是对 A 的上浮。

sink(下沉)

如果某个节点 A 比它的子节点(中的一个)小,那么 A 就不配做父节点,应该下去,下面那个更大的节点上来做父节点,这就是对 A 进行下沉。

优先队列(PriorityQueue)

优先队列不再遵循先入先出的原则:

  • 最大优先队列,不管入队顺序,当前最大的元素优先出队。
  • 最小优先队列,不管入队顺序,当前最小的元素优先出队。

为了实现这个目的,就需要新增加的元素进行排序,让最大或者最小的元素在队列顶部。因此可以使用二叉堆进行设计。

优先级队列有两个主要 API,分别是 insert 插入一个元素和 delMax 删除最大元素(如果底层用最小堆,那么就是 delMin)

insert 入队

入队时在二叉堆的堆底部增加新的元素,然后再进行上浮下沉操作,保持二叉堆的结构。
请添加图片描述

delMin 出队

出队时,删除二叉堆的堆顶元素,然后将堆底元素替换到顶部,再进行上浮下沉操作,保持二叉堆的结构。
请添加图片描述

C++的STL库中有优先队列,Java也提供了这种数据结构。
C# 在.Net 6当中也增加了优先队列,有大佬已经解析了源码,大概花个10分钟就能看完。
源码解析C#中PriorityQueue(优先级队列)的实现

参考

漫画:什么是优先队列?
源码解析C#中PriorityQueue(优先级队列)的实现
二叉堆详解并实现优先级队列

猜你喜欢

转载自blog.csdn.net/weixin_44394801/article/details/122657684