概述

与FIFO的普通队列不同,在优先级队列中,元素出队顺序是由元素的优先级决定。比如大根堆是最大的元素先出队,小根堆是最小的元素先出队。
堆是实现优先级队列效率很高的数据结构(当然我们也可以使用无序的线性表或者有序链表来实现,但是它们的删除、插入的时间复杂度至少有一个是O(n))。堆是一棵完全二叉树,这样就保证了底层存储的数组拥有很高的空间利用率。无论是大根堆还是小根堆,它们的插入和删除的复杂性都是O(height of tree)也就是O(log n)。
堆的底层实现是数组,但是逻辑上我们将它映射到一棵完全二叉树上。它的插入操作是从数组的末尾的下一个位置也就是完全二叉树的下一个新增的叶子节点开始,逐层遍历它的父节点、祖父节点…直到找到合适的插入位置或者达到根部。反之,它的删除操作则是首先将根节点也就是数组的[0]元素出队,然后从上到下逐层选择合适左右孩子进行遍历。

大根堆的实现

其他例如优先队列ADT或者堆空的自定义异常类等一些辅助类这里就省略了,它们与以前其他数据结构中的实现大同小异 。

#pragma once
#ifndef MAXHEAP_H
#define MAXHEAP_H#include "emptyHeap.h"
#include "priorityQueueADT.h"
//堆空异常 借用了队列的异常类
#include "..//..//..///ch09/Queue/Queue/queueEmpty.h"
#include "..//..//..//ch06/ChainList/ChainList/illegalParameterValue.h"//===================================最大堆的定义实现======================================
template <typename T>
class maxHeap :public priorityQueue<T> {public:maxHeap(size_t _capacity=10);//默认构造函数~maxHeap() { delete[] heap; }bool empty()const { return heapSize == 0; }size_t size()const { return heapSize; }T& top()const;void pop();void push(const T& _element);void heapInitial(T* arr,size_t arrSize);//将给定数组转为最大堆void output(std::ostream& os)const;
private:T* heap;         //优先级队列(堆)数组size_t capcacity;//堆的容量size_t heapSize; //堆的元素个数
};template <typename T>
inline maxHeap<T>::maxHeap(size_t _capacity) {if (_capacity <= 1)throw illegalParameterValue("initial capacity must be >=1 ");capcacity = _capacity + 1;//因为heap[0]不用heap = new T[_capacity];heapSize = 0;
}template <typename T>
inline T& maxHeap<T>::top()const {if (heapSize == 0)throw emptyHeap("Can not get top element on empty Heap!");return heap[1];
}template <typename T>
void maxHeap<T>::push(const T& _element) {if (heapSize == capcacity - 1){//除开heap[0] 数组容量已满T* new_heap = new T[2 * capcacity];std::copy(heap, heap+capcacity+1, new_heap);delete[] heap;heap = new_heap;}size_t pos = ++heapSize;//要插入的位置//在完全二叉树中多出一个位置为++heapSize的节点,从要插入的元素_element的父节点//也就是heap[pos/2]开始逐级向上比较,直到找到要插入的元素在大根堆中的位置(大于子节点且小于父节点)while (pos != 1 && heap[pos/2]<_element) {//最大的话则插入根节点heap[pos] = heap[pos / 2];pos /= 2;//继续向上层比较}//比较完成 插入该元素heap[pos] = _element;
}template <typename T>
void maxHeap<T>::pop() {if (heapSize == 0)throw emptyHeap("Can not pop on empty Heap!");//首先删除根节点也就是heap[1]的元素 然后逐级遍历选取左右孩子中最大的一个移动到该层级来//最后将完全二叉树中最末尾的元素也即是heap[heapSize]的元素移动到空缺的位置 最后删除末尾节点heap[1].~T();//删除根节点元素T lastElement = heap[heapSize--];//重新把最末尾的元素放到合适的位置 同时重构堆int pos = 1;//要插入的位置int child = 2;//它的孩子while (child<=heapSize) {//是左孩子大还是右孩子大?if (child < heapSize && heap[child] < heap[child + 1])++child;//选择右孩子作为下一个pos//可以在这层插入吗?if (lastElement > heap[child])break;//找到位置//否则将大孩子放入pos 移动到下层进行比较heap[pos] = heap[child];pos = child;child *= 2;}//找到位置 插入heap[pos] = lastElement;
}template <typename T>
void maxHeap<T>::heapInitial(T* arr,size_t arrSize) {//将给定数组转为堆delete[] heap;//首先释放原有堆heapSize = arrSize;capcacity = 2*arrSize;//构造一个新的堆数组 heap = new T[capcacity + 1];std::copy(arr,arr+arrSize,heap+1); //heap[0]需要空出来//初始化为堆for (int root = heapSize / 2; root > 0;--root) {//从倒数第二层依次遍历到heap[1]进行调整int child = 2 * root;//其孩子节点T rootElement = heap[root];//从上到下依次调整while (child<=heapSize) {//找到左右孩子中大的一个if (child < heapSize && heap[child] < heap[child + 1])++child;//右孩子大//当前位置是否可以插入if (heap[child] < rootElement)break;//可以插入 跳出//不可以插入 调整并且继续移动到下层heap[child / 2] = heap[child];child *= 2;}//找到合适的插入位置heap[child / 2] = rootElement;}
}template <typename T>
void maxHeap<T>::output(std::ostream& os)const {for (size_t i = 1; i <= heapSize;++i) {os << heap[i] << ends;}os << endl;
}template <typename T>
std::ostream& operator<<(std::ostream& os, const maxHeap<T>& heap) {heap.output(os);return os;
}#endif // !MAXHEAP_H

小根堆的实现

小根堆的实现和大根堆的实现一模一样,只是在插入或者删除以及堆化一个给定数组的时候,对类型T的判断条件相反。即大根堆如果元素大于其父节点则将父节点下移,而小根堆相反,如果元素小于其父节点则将父节点下移。

#pragma once
#ifndef MINHEAP_H
#define MINHEAP_H//小根堆跟大根堆的实现一模一样 只是调整树结构的时候是将小的放在根节点
//大的元素放在左右节点#include "priorityQueueADT.h"
#include "emptyHeap.h"
#include "..//..//..///ch09/Queue/Queue/queueEmpty.h"//===================================最小堆的定义实现======================================
template <typename T>
class minHeap :public priorityQueue<T> {public:minHeap(size_t _capacity = 10) :capacity(_capacity+1),heapSize(0),heap(new T[capacity+1]){ }~minHeap() { delete[] heap; }bool empty()const { return heapSize == 0; }size_t size()const { return heapSize; }T& top()const {if (heapSize == 0)throw emptyHeap("Can not get top element on emtpy heap");return heap[1];}void push(const T& _element);void pop();void heapInitial(T* arr, size_t arrSize);//将给定数组转为最小堆void output(std::ostream& os)const;
private:size_t capacity;size_t heapSize;T* heap;
};//插入操作是从下向上依次调整
template <typename T>
void minHeap<T>::push(const T& _element) {if (heapSize == capacity - 1) {T* new_heap = new T [2 * capacity];std::copy(heap, heap + capacity+1, new_heap);delete heap;heap = new_heap;}//依次向上调整int pos = ++heapSize;while (pos>=1 && _element < heap[pos / 2]) {heap[pos] = heap[pos / 2];pos /= 2;}heap[pos] = _element;
}//pop操作则是从上到下一次调整
template <typename T>
void minHeap<T>::pop() {if (heapSize <= 0)throw emptyHeap("Can not pop on empty heap");heap[1].~T();//删除并析构堆顶元素T lastElement = heap[heapSize--];//保存最后的一个元素int child = 2;//从第二层开始向下遍历while (child<=heapSize) {if (child<heapSize && heap[child]>heap[child + 1])++child;//选择左右孩子中最小的那个if (lastElement < heap[child])break;//找到可以插入的位置heap[child / 2] = heap[child];//调整child *= 2;//移动到下层}heap[child / 2] = lastElement;
}//初始化一个数组为最小堆 同样是从上到下进行遍历调整
template <typename T>
void minHeap<T>::heapInitial(T* arr,size_t arrSize) {delete[] heap;//释放原有heap数组heapSize = arrSize;capacity = 2 * arrSize;heap = new T[capacity + 1];std::copy(arr, arr + arrSize, heap + 1);//堆化for (int root = heapSize / 2; root > 0;--root) {T rootElement = heap[root];int child = 2 * root;while (child <= heapSize) {if (child<heapSize && heap[child]>heap[child + 1])++child;//找到左右孩子中最小的那个if (rootElement < heap[child])break;//找到可以插入的位置heap[child / 2] = heap[child];child *= 2;}heap[child / 2] = rootElement;}
}template <typename T>
void minHeap<T>::output(std::ostream& os)const {for (size_t i = 1; i <= heapSize; ++i) {os << heap[i] << ends;}os << endl;
}template <typename T>
std::ostream& operator<<(std::ostream& os, const minHeap<T>& heap) {heap.output(os);return os;
}#endif // !MINHEAP_H

优先级队列--大根堆和小根堆相关推荐

  1. 【数据结构】堆,大根堆,小根堆,优先队列 详解

    目录 堆 1.堆的数组实现 2.小根堆 3.大根堆 4.优先队列 例题 1.SP348 EXPEDI - Expedition(有趣的贪心思路,优先队列) 2.合并果子 堆 要了解堆之前,请先了解树, ...

  2. 堆(大根堆、小根堆)

    完全二叉堆 堆又可称之为完全二叉堆.这是一个逻辑上基于完全二叉树.物理上一般基于线性数据结构(如数组.向量.链表等)的一种数据结构. 完全二叉树的存储结构 学习过完全二叉树的同学们都应该了解,完全二叉 ...

  3. 大根堆和小根堆的区别

    大根堆和小根堆的区别 文章转自:https://blog.csdn.net/weixin_37197708/article/details/79546535 堆的概念 堆实际上是一棵完全二叉树,其任何 ...

  4. 堆结构 - 大根堆、小根堆

    在开发语言中,heap在使用层次的名字叫PriorityQueue(优先级队列),PriorityQueue数据结构的名字就叫做堆,底层就是用堆结构实现的. 完全二叉树 空树也算是完全二叉树 每一层都 ...

  5. 堆(Heap)大根堆、小根堆

    目录 堆(Heap)大根堆.小根堆 1.堆的存储: 2.堆的操作:insert 3.堆的操作:Removemax 4.堆的操作:buildHeap 堆化数组 5.堆排序 堆(Heap)大根堆.小根堆 ...

  6. 【堆】 大根堆和小根堆的建立

    堆是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于(或不小于)其左孩子和右孩子节点的值. (1)根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最小者的堆称为小根堆. (1)根结点(亦 ...

  7. C语言实现选择排序——堆排序(大根堆、小根堆)

    C语言实现堆排序 文章目录 C语言实现堆排序 大根堆排序算法 1.交换操作 2.对结点进行调整为大根堆 3.建立大根堆 4.大根堆排序算法实现 小根堆排序算法 1.交换操作 2.对结点进行调整为小根堆 ...

  8. 浅谈大根堆,小根堆,以及堆排序(python)实现

    既然要说堆排序,那么必然要说说什么是大根堆,小根堆了. 大根堆: 若根节点存在左右子节点,那么根节点的值大于或等于左右子节点的值. 小根堆: 若根节点存在左右子节点,那么根节点的值小于或等于左右子节点 ...

  9. 大根堆、小根堆(数组模拟操作)

    1.什么是大根堆.小根堆? 首先堆应该是一颗完全二叉树,大根堆就是二叉树的所有父节点的值都比左右孩子的值大,小根相反.下面是大根堆和小根堆的图: 如上,左图是一个大根堆,右图是一个小根堆. 2.树的数 ...

最新文章

  1. 2017 计蒜之道 初赛 第五场 B. UCloud 的安全秘钥(简单)
  2. 动态切换站点样式(换皮肤)
  3. php rabbmq教程_RabbitMQ+PHP 教程六(RPC)
  4. NRF52832编译micro-ecc是指编译器路径
  5. rabbitmq java集群_RabbitMQ集群整合SpringBoot2.x
  6. 【AI不惑境】网络宽度对模型性能有什么影响?
  7. GNN大有可为,从这篇开始学以致用
  8. python归并排序 分词_python实现归并排序,归并排序的详细分析
  9. 后台获取数据排序后在网页显示(Comparator)
  10. ae目标区域_中班区域活动目标
  11. 【kafka】记一次线上kafka一直rebalance故障 消费慢 数据积压
  12. 微软开源 Outlook for iOS 暗黑模式解决方案:支持 iOS 11 及更高版本
  13. 怎么用eclipse编写python_python用eclipse开发配置
  14. 【loj3120】【CTS2019】珍珠
  15. 忘了微信密码怎么办_微信支付密码怎么改?微信支付密码忘了怎么办?详细教程来了!...
  16. STM32基础11--模数转换(ADC)
  17. 公司会议如何保证高效
  18. java catch 空指针异常_在Java中避免空指针异常(Null Pointer Exception)
  19. android 资源图片加密
  20. 云服务器liunx系统怎么安装,云服务器怎么安装linux系统

热门文章

  1. 在ajax异步请求服务器报500万能解决方法
  2. 英语作文集(升本用的)
  3. 长沙理工大学第十二届ACM大赛 I.主持人的烦恼【贪心】
  4. UGNX Imachining VoluMill动态与高速铣视频教程
  5. 【人工智能】身边的人工智能
  6. 数据库引擎InnoDB与MyISAM区别
  7. redis list 实现消息队列 多线程消费
  8. 未来科技科幻电影全息效果HUD Ultimate FUI HUD Library
  9. Keras深度学习使用VGG16预训练神经网络实现猫狗分类
  10. IEEE 754浮点数简介与C代码实现