CPP学习之priority_queue的使用及模拟实现
1. 介绍
priority_queue是一种容器适配器,内部元素按照升序或降序排列,因为是queue的一种,所以遵循先入先出原则(FIFO),底层数据结构采用堆,默认是大堆,底层数据容器默认采用vector,当然也可以采用其他支持随机访问(在常数时间O(1)内访问至任意位置的元素)的容器。
容器适配器是将特定的容器类封装成其底层容器类的容器。
适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该模式是将一个类的接口转换为客户希望的另一个接口。
2. 用法
priority_queue的常用接口:
使用举例:
#include <queue>
#include <functional> //greater或less算法的头文件void test_1()
{priority_queue<int, vector<int>, less<int>> pql; //less建大堆(降序),greater建小堆(升序)pql.push(3);pql.push(2);pql.push(5); pql.push(1);pql.push(9);//每次调整堆都是O(logN),因为N代表堆的元素个数,logN代表堆的层数int size = pql.size();for (int i = 0; i < size; i++){cout << pql.top() << " ";pql.pop();}cout << endl;
}
在创建priority_queue对象时,需要填写模板参数,这些模板参数都是类型。
如果插入的元素是自定义类型,那么就需要重载 < 或 > ;
比如下面的日期类
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}bool operator<(const Date& d)const{return (_year < d._year) ||(_year == d._year && _month < d._month) ||(_year == d._year && _month == d._month && _day < d._day);}bool operator>(const Date& d)const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}friend ostream& operator<<(ostream& _cout, const Date& d){_cout << d._year << "-" << d._month << "-" << d._day;return _cout;}
private:int _year;int _month;int _day;
};
3. 模拟实现
模拟实现代码如下:
my_priority_queue.h
#pragma once
#include<iostream>
#include<queue>
#include<vector>
#include<list>using namespace std;template<class T>
class my_less
{
public:bool operator()(const T& x, const T& y){return x < y;}
};template<class T>
class my_greater
{
public:bool operator()(const T& x, const T& y){return x > y;}
};template<class T, class container = vector<T>, class Compare = my_less<T>> //默认建大堆
class my_priority_queue
{
private:container _con;void adjust_down(int parent) //向下调整{Compare com;int child = parent * 2 + 1; //左孩子int size = _con.size();if (child < size - 1 && com(_con[child], _con[child + 1])) //如果左孩子小于右孩子,就用右孩子{child += 1;}while (child < size){if (com(_con[parent], _con[child])){swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}}void adjust_up(int child) //向上调整{Compare com;int parent = (child - 1) / 2;while (child > 0){if (com(_con[parent], _con[child])){swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}public:my_priority_queue(){}template<class input_iterator>my_priority_queue(input_iterator first, input_iterator last){while (first != last){_con.push_back(*first);++first;}for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--) //从最后一个叶子节点的父节点开始,向下调整{adjust_down(i);}}void push(const T& val){_con.push_back(val);adjust_up(_con.size() - 1); //尾部插入数据后,这个数据进行向上调整}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjust_down(0);}T& top(){return _con.front();}bool empty(){return _con.empty();}size_t size(){return _con.size();}
};