概述
与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