优先级队列

1|0优先级队列使用二叉堆实现的

插入元素和删除队列中最大的元素时间复杂度都是O(logn),因为这俩个操作是基于二叉堆的上浮和下沉操作实现的

2|0二叉堆是什么?

二叉堆逻辑结构是完全二叉树,存储结构是数组

3|0二叉堆是怎么存的呢?

// 父节点的索引 int parent(int root) { return root / 2; } // 左孩子的索引 int left(int root) { return root * 2; } // 右孩子的索引 int right(int root) { return root * 2 + 1; }

如图:数组索引0的位置专门置空

4|0优先级队列的实现

public class MaxPQ { private Integer[] pq; // 当前 Priority Queue 中的元素个数 private int N = 0; public MaxPQ(int cap) { // 索引 0 不用,所以多分配一个空间 pq = new Integer[cap + 1]; } public static void main(String[] args) { MaxPQ pq=new MaxPQ(5); pq.insert(5); pq.insert(4); pq.insert(3); System.out.println(pq.max());//5 pq.delMax(); System.out.println(pq.max());//4 pq.insert(10); System.out.println(pq.max());//10 } /* 返回当前队列中最大元素 */ public int max() { return pq[1]; } /* 插入元素 e */ public void insert(int e) { N++; // 先把新元素加到最后 pq[N] = e; // 然后让它上浮到正确的位置 swim(N); } /* 删除并返回当前队列中最大元素 */ public int delMax() { // 最大堆的堆顶就是最大元素 int max = pq[1]; // 把这个最大元素换到最后,删除之 exch(1, N); pq[N] = null; N--; // 让 pq[1] 下沉到正确位置 sink(1); return max; } /* 上浮第 k 个元素,以维护最大堆性质 */ private void swim(int k) { // 如果浮到堆顶,就不能再上浮了 while (k > 1 && less(parent(k), k)) { // 如果第 k 个元素比上层大 // 将 k 换上去 exch(parent(k), k); k = parent(k); } } /* 下沉第 k 个元素,以维护最大堆性质 */ private void sink(int k) { // 如果沉到堆底,就沉不下去了 while (left(k) <= N) { // 先假设左边节点较大 int older = left(k); // 如果右边节点存在,比一下大小 if (right(k) <= N && less(older, right(k))) older = right(k); // 结点 k 比俩孩子都大,就不必下沉了 if (less(older, k)) break; // 否则,不符合最大堆的结构,下沉 k 结点 exch(k, older); k = older; } } /* 交换数组的两个元素 */ private void exch(int i, int j) { int temp = pq[i]; pq[i] = pq[j]; pq[j] = temp; } /* pq[i] 是否比 pq[j] 小? */ private boolean less(int i, int j) { return pq[i] < pq[j]; } // 父节点的索引 int parent(int root) { return root / 2; } // 左孩子的索引 int left(int root) { return root * 2; } // 右孩子的索引 int right(int root) { return root * 2 + 1; } }

5|0总结

  • 二叉堆就是一种完全二叉树,所以适合存储在数组中,而且二叉堆拥有一些特殊性质。

  • 二叉堆的操作很简单,主要就是上浮和下沉,来维护堆的性质(堆有序),核心代码也就十行。

  • 优先级队列是基于二叉堆实现的,主要操作是插入和删除。插入是先插到最后,然后上浮到正确位置;删除是调换位置后再删除,然后下沉到正确位置。核心代码也就十行。


__EOF__

本文作者程序员小宇
本文链接https://www.cnblogs.com/treasury/p/12752861.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   程序员小宇  阅读(184)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示