目录
适配器
priority_queue
priority_queue的使用
priority_queue模拟实现
适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),适配器是将一个类的接口转换成客户希望的另外一个接口。
举个栗子, 咱们香港的插头和我们内地是不一的, 如下图, 这种插头在咱们内地是不方便使用的, 要是香港同胞到对岸深圳转一转, 被繁华的深圳所吸引, 不禁多留了两天, 那这时候手机要充电怎么充电啊, 不过没关系, 我们有适配器, 其实真正给手机充电的还是手机充电器, 适配器只是方便了人们的使用而已.
常见的容器适配器有stack , queue, priority_queue, 它们就相当于上图的适配器, 真正给手机充电的是还是充电头, 同样的道理, 它们底层是靠别的容器实现的
例如:
stack可以用vector, deque, list实现.
queue可以用 deque, list实现
priority_queue, 可以用 deque, vector实现C++STL容器适配器之queue
C++ STL容器适配器之stack
简介
优先队列priority_queue是一个堆
堆数据结构详解链接1. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。但容器必须可以通过随机访问迭代器访问,并支持以下操作:
empty():检测容器是否为空
size():返回容器中有效元素个数
front():返回容器中第一个元素的引用
push_back():在容器尾部插入元素
pop_back():删除容器尾部元素
2. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。
3. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作。算法头文件 #include
4. priority_queue 的使用需要头文件 #include
5. 所有需要用到堆的时候,都可以考虑使用priority_queue。注意: 默认情况下priority_queue是大堆。如果要创建小堆,需要将第三个模板参数换成greater比较方式priority_queue图示:
所有需要用到堆的时候,都可以考虑使用priority_queue。注意: 默认情况下priority_queue是大堆。如果要创建小堆,需要将第三个模板参数换成greater比较方式
函数名称 | 接口说明 |
---|---|
priority_queue()
|
构造一个空的优先级队列 |
priority_queue(first, last) |
将[first, last)范围内所有的数据构造成一个新的优先队列 |
empty( ) | 检测优先级队列是否为空,是返回true,否则返回 false |
top( ) | 返回优先级队列中最大(最小元素),即堆顶元素 |
push(x) | 在优先级队列中插入元素x |
pop() | 删除优先级队列中最大(最小)元素,即堆顶元素 |
注意 :
1. 默认priority_queue底层实现用vector, 默认是大堆
如果要用deque实现或, 创建小堆, 需要传入模板参数, priority_queue共有三个模板参数, 第一个是数据类型, 后两个是缺省参数, 第二个缺省值是vector, 第三个缺省值是less
下面创建的priority_queue依次是, 用deque实现的大根堆, 用vector实现的小根堆, 用deque实现的小根堆priority_queue
> pq1; priority_queue , greater > pq2; priority_queue , greater > pq3; 需要注意的是, 缺省值less和greater是仿函数, 需要头文件#include
仿函数: 可以当成函数使用的类,因为类中重载了函数调用运算符(或小括号运算符) "()"
2. 如果在priority_queue中放自定义类型的数据,用户需要在自定义类型中提供> 或者< 的重载。因为less和greater这两个仿函数(类)中重载的()运算符 中只是简单地用> , <比较, 如自定义类型不能直接比较则会出错 .
例如, 自定义类型Date类, 时间的比较, 未重载>, <则不能比较, 所以需要我们在Date类中重载>, <运算符, 如下
class Date { int _year; int _month; int _day; 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; } };
3. 有些情况下,用户可能需要提供比较器规则
如果priority_queue
pq; 传入的是Date类对象的指针, 就算我们在Date类中重载了><的也不能对两个地址进行比较, 所以我们要自己提供比较器, 也就是要自己写一个仿函数(类), 重载一下小括号运算符(). 如下:
这个自己提供的比较器可以是类模板, 也可以是普通类, 模板类就可以实例出其他的指针类型class Less1 { public: bool operator()(const Date* pLeft, const Date* pRight) { return *pLeft < *pRight; } }; template
class Less2 { public: bool operator()(const T pLeft, const T pRight) { return *pLeft < *pRight; } }; priority_queue , Less1> pq1; priority_queue , Less2 > pq2;
头文件priority_queue.h
#pragma once
#include
#include
#include
#include
using namespace std;
template
class Greater {
public:
bool operator()(const T& left, const T& right){
return left > right;
}
};
template
class Less {
public:
bool operator()(const T& left, const T& right) {
return left < right;
}
};
template, class Cmp = Less>
class my_priority_queue {
Con m_data;
Cmp m_cmp;
public:
my_priority_queue() {
}
template
my_priority_queue(InputIterator first, InputIterator last)
: m_data(first, last){
make_heap(m_data.begin(), m_data.end(), m_cmp);
}
void push(const T& val) {
m_data.push_back(val);
push_heap(m_data.begin(), m_data.end(), m_cmp);
}
void pop() {
pop_heap(m_data.begin(), m_data.end(), m_cmp);
m_data.pop_back();
}
T& top() {
return m_data.front();
}
int size() {
return m_data.size();
}
bool empty() {
return m_data.empty();
}
};
测试入口main.cpp
#include
#include"priority_queue.h"
#include
#include
#include
using namespace std;
void Test_priority_queue() {
cout << "STL中的priority_queue\n";
priority_queue pq;
for (int i = 1; i <= 5; ++i) {
pq.push(i);
}
cout << "size = " << pq.size() << endl;
for (int i = 1; !pq.empty(); i *= 2) {
for (int j = i; !pq.empty() && j > 0; --j) {
cout << pq.top() << ' ';
pq.pop();
}
cout << endl;
}
cout << "size = " << pq.size() << endl;
}
void Test_my_priority_queue() {
cout << "自己实现的的priority_queue\n";
my_priority_queue, Less> pq;
//my_priority_queue pq;
for (int i = 1; i <= 5; ++i) {
pq.push(i);
}
cout << "size = " << pq.size() << endl;
for (int i = 1; !pq.empty(); i *= 2) {
for (int j = i; !pq.empty() && j > 0; --j) {
cout << pq.top() << ' ';
pq.pop();
}
cout << endl;
}
cout << "size = " << pq.size() << endl;
}
int main() {
Test_priority_queue();
Test_my_priority_queue();
system("pause");
return 0;
}
运行结果 :