优先队列及堆
1.优先队列是一个数据结构,队列中的记录是有关键字的,它支持两个基本操作:插入新记录和删除关键字最大的记录。
2.堆排序,如果一棵树中每个节点中的关键字都大于或等于所有子节点中的关键字,就称它为按堆排序。
若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。完全二叉树中,第i个元素是第2i个元素和第2i+1个元素的父亲。
堆是一个节点集合,其中的关键字排放在一个堆排序的完全二叉树中,表示为一个数组。
3.自底向上堆化
当一个节点的优先级提高了,为了重构堆,我们从堆的下方不断往上移动,交换节点k和它的父节点(k/2)。如果需要,继续交换直到a[k/2]<a[k]或者直到我们到达堆的顶部。
1 template <class Item> 2 void fixUp(Item a[], int k) 3 { 4 while ( k > 1 && a[k/2] < a[k]) 5 { 6 exch(a[k], a[k/2]); 7 k = k/2; 8 } 9 }
4.自顶向下堆化
当一个节点的优先级下降后,为了重构,我们从堆的上部向下移动,如果必要的话,把节点k和它的较大节点互换,直到在位置k的节点的子节点都小于k节点或者k节点已经在堆的底部。注意,如果N是偶数而k=N/2,那么在位置k的节点只有一个子节点——这种情况必须适当处理。
在这个程序里的内部循环由两个特殊出口:一个是到达了堆的底部,另一个是在堆的内部已经符合堆的条件了。这是一个“break”结构的原型例子。
1 template <class Item> 2 void fixDown(Item a[], int k, int N) 3 { 4 while (2*k <= N) 5 { 6 int j = 2*k; 7 if (j < N && a[j] < a[j+1]) j++; 8 if (!(a[k] < a[j])) break; 9 exch(a[k], a[j]); 10 k = j; 11 } 12 }
5.基于堆的优先队列
为了实现insert操作,我们把N增加1,把最新的元素加入到堆的末尾,然后用fixUp操作来重构堆。对于getmax操作,堆的大小要减1,然后我们得到pq[1]的值,再把pq[N]移到pq[1]来减少堆的大小,接着用fixDown操作重构堆。数组的第一个位置pq[0]是不用的,但可以作为一些实现的标志。
1 template <class Item> 2 class PQ 3 { 4 private: 5 Item *pq: 6 int N; 7 public: 8 PQ(int maxN) 9 {pq = new Item[maxN+1]; N = 0;} 10 int empty() const 11 {return N == 0;} 12 void insert(Item item) 13 {pq[++N] = item; fixUp(pq, N);} 14 Item getmax() 15 { 16 exch(pq[1], pq[N]); 17 fixDown(pq, 1, N-1); 18 return pq[N--]; 19 } 20 };
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?