一、优先级队列
1、 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。
2、 优先级队列类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。
3、 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。
4、 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问,并支持以下操作:
empty():检测容器是否为空
size():返回容器中有效元素个数
front():返回容器中第一个元素的引用
push_back():在容器尾部插入元素
优先级队列的底层是一个数据结构中的堆。优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。注意:默认情况下priority_queue大堆。
二、仿函数
我们知道,堆分为大堆和小堆,而STL中提供的容器默认为大堆,但是在实际应用中我们往往也需要小堆。那么我们应该怎样来得到小堆呢?
从文档中,我们发现优先级队列的模板参数中的第三个参数叫Compare,他其实就是一个进行比较的仿函数。
1、仿函数,又称函数对象,它是一个类,是一个重载了运算符()的一个类。类对象可以像函数一样调用。
namespace dbln { /* 仿函数(函数对象)是一个类,是一个重载了()的类 类对象可以像函数一样去使用*/ template<class T> class less { public: bool operator()(const T& l, const T& r)const { return l < r; } }; template<class T> class greater { public: bool operator()(const T& l, const T& r)const { return l > r; } }; }
三、 成员函数
1、push 和 向上调整算法
向上调整算法
void adjust_up(size_t child) { Compare com; size_t parent = (child - 1) / 2; while (child > 0) { //if (_con[parent] < _con[child]) if (com(_con[parent], _con[child])) { std::swap(_con[parent], _con[child]); child = parent; parent = (child - 1) / 2; } else { break; } } }
push
void push_back(const T& x) { _con.push_back(x); adjust_up(_con.size() - 1); }
2、pop 和 向下调整算法
向下调整算法
void adjust_down(size_t parent) { Compare com; size_t child = parent * 2 + 1; while (child < _con.size()) { //if (child + 1 < _con.size() && _con[child] < _con[child + 1]) if (child + 1 < _con.size() && com(_con[child], _con[child + 1])) { child++; } //if (_con[child] > _con[parent]) if (com(_con[parent], _con[child])) { std::swap(_con[child], _con[parent]); parent = child; child = parent * 2 + 1; } else { break; } } }
pop
//删除堆顶 void pop() { std::swap(_con[0], _con[_con.size() - 1]); _con.pop_back(); adjust_down(0); }
3、top
const T& top() { return _con[0]; }
4、empty
bool empty()const { return _con.empty(); }
5、size
size_t size()const { return _con.size(); }
6、区间构造函数
template<class InputIterator> priority_queue(InputIterator first, InputIterator last) { while (first != last) { _con.push_back(*first); } for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--) { adjust_down(i); } }
四、总代码
priority_queue.h
#pragma once #include<iostream> #include<vector> using namespace std; //优先级队列的底层是一个堆 namespace zdl { //Compare进行比较的仿函数,less是大堆 greater是小堆 template<class T, class Contatiner = vector<T>, class Compare = std::less<T>> class priority_queue { public: template<class InputIterator> priority_queue(InputIterator first, InputIterator last) { while (first != last) { _con.push_back(*first); } for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--) { adjust_down(i); } } priority_queue() {} void adjust_up(size_t child) { Compare com; size_t parent = (child - 1) / 2; while (child > 0) { //if (_con[parent] < _con[child]) if (com(_con[parent], _con[child])) { std::swap(_con[parent], _con[child]); child = parent; parent = (child - 1) / 2; } else { break; } } } void adjust_down(size_t parent) { Compare com; size_t child = parent * 2 + 1; while (child < _con.size()) { //if (child + 1 < _con.size() && _con[child] < _con[child + 1]) if (child + 1 < _con.size() && com(_con[child], _con[child + 1])) { child++; } //if (_con[child] > _con[parent]) if (com(_con[parent], _con[child])) { std::swap(_con[child], _con[parent]); parent = child; child = parent * 2 + 1; } else { break; } } } void push(const T& x) { _con.push_back(x); adjust_up(_con.size() - 1); } //删除堆顶 void pop() { std::swap(_con[0], _con[_con.size() - 1]); _con.pop_back(); adjust_down(0); } const T& top() { return _con[0]; } bool empty()const { return _con.empty(); } size_t size()const { return _con.size(); } private: Contatiner _con; }; }
test.cpp
#include"PriorityQueue.h" namespace dbln { /* 仿函数(函数对象)是一个类,是一个重载了()的类 类对象可以像函数一样去使用*/ template<class T> class less { public: bool operator()(const T& l, const T& r)const { return l < r; } }; template<class T> class greater { public: bool operator()(const T& l, const T& r)const { return l > r; } }; } void test_priorityQueue() { zdl::priority_queue<int> q; q.push(1); q.push(2); q.push(4); q.push(77); q.push(75); q.push(23); q.push(9); while (!q.empty()) { cout << q.top() << " "; q.pop(); } cout << endl; } int main() { dbln::less<int> isfunc; cout << isfunc(1, 2) << endl; test_priorityQueue(); return 0; }