从零开始手写STL库–Priority_Queue的实现
Gihub链接:miniSTL
文章目录
- 从零开始手写STL库–Priority_Queue的实现
- 一、priority_queue是什么?
- 二、堆是什么?
- 三、priority_queue要包含什么函数
- 总结
一、priority_queue是什么?
优先队列在力扣刷题中可能会出现,实际上就是一个带有权重优先级的队列
在这个队列中,所有元素都会有一个权重,队列会根据权重来对元素排序
这也就是所谓的“优先”,而这个优先顺序是可以自己定义的
对int型优先队列,STL库默认是把数据从大到小排序的
所以难点在于如何排序,答案是基于堆来构建优先队列
那么问题也就明确了,所谓优先队列的考察,实际上是对数据结构–堆的考察
二、堆是什么?
堆(Heap)是一种特殊的完全二叉树,它满足下面的性质:
结构性质: 堆是一个完全二叉树,这意味着除了最后一层外,每一层都是完全填满的,而最后一层的节点则尽可能地集中在左边。
堆性质: 在一个最大堆(Max Heap)中,每个节点的值都大于或等于其子节点的值,根节点的值是堆中的最大值。相反,在一个最小堆(Min Heap)中,每个节点的值都小于或等于其子节点的值,根节点的值是堆中的最小值。
实际上堆可以用队列实现,不需要真的构建一个二叉树,只需要构建两个维护函数即可
三、priority_queue要包含什么函数
首先明确一下两个维护函数,即向上维护和向下维护
void heapUp(){int index = data.size() - 1;while (index){int parentIndex = (index - 1) / 2;if(data[index] > data[parentIndex]){std::swap(data[index], data[parentIndex]);index = parentIndex;}else break;}}void heapDown() {int index = 0;int size = data.size();while (1) {int leftChild = 2 * index + 1;int rightChild = 2 * index + 2;int largest = index;if (leftChild < size && data[leftChild] > data[largest]) largest = leftChild;if (rightChild < size && data[rightChild] > data[largest]) largest = rightChild;if (largest != index) {std::swap(data[index], data[largest]);index = largest;} else break;}}
本处实现就不考虑string或者其他类型的队列了,只考虑int和double型队列
这里向上向下维护实际上就是堆排序的上浮和下沉
上浮:如果父节点比k结点小,就交换他们的位置
下沉:如果k结点比它的两个子结点小,则与较大的那个交换
之后就是正常的一层双向队列封装,只需要每次插入和删除的时候维护一下堆即可
template <typename T, typename Container = myDeque<T> >
class myPriQue
{
private:Container data;void heapUp(){int index = data.size() - 1;while (index){int parentIndex = (index - 1) / 2;if(data[index] > data[parentIndex]){std::swap(data[index], data[parentIndex]);index = parentIndex;}else break;}}void heapDown() {int index = 0;int size = data.size();while (1) {int leftChild = 2 * index + 1;int rightChild = 2 * index + 2;int largest = index;if (leftChild < size && data[leftChild] > data[largest]) largest = leftChild;if (rightChild < size && data[rightChild] > data[largest]) largest = rightChild;if (largest != index) {std::swap(data[index], data[largest]);index = largest;} else break;}} public:myPriQue() {};myPriQue(const Container & c) : data(c) {int size = data.size();for(int i = (size / 2) - 1; i >= 0; i --) heapDown();}void push(const T & value){data.push_back(value);heapUp();}void pop(){if (!data.empty()){std::swap(data[0], data[data.size() - 1]);data.pop_back();heapDown();}else throw std::runtime_error("Stack is empty!");}T& top() {if (!data.empty()) return data[0];else throw std::runtime_error("Priority queue is empty.");}bool empty() {return data.empty();}size_t size() const {return data.size();}
};
总结
优先队列一般也不会作为考察重点,在力扣中更多地是考虑如何利用vector或者queue自己构建一个专属的优先队列来解决问题,比如单调栈,实际上也是一种优先队列
只需要知道优先队列是以堆为基础构建的即可
至此,简单STL库实现教程完成。由于本人初学,博客中或许会有不对之处,也请读者指出,完整代码异步GitHub链接。