priority_queue 优先级队列
插入容器内的数据,按降序排列方式被取出
-最先取出的数据,是队列中,值最大的那个
// C++学习笔记_20 适配器容器- priority_queue
//
#include<iostream>
#include<string>
#include<queue>
using namespace std;
class AAA
{
private:
int x;
int y;
public:
AAA():x(0),y(0){}
AAA(int a, int b) :x(a), y(b){}
friend ostream& operator << (ostream& os, const AAA &A)
{
os << "(" << A.x << ", " << A.y << ")";
return os;
}
//二进制“ < ” : 没有找到接受“const AAA”类型的左操作数的运算符(或没有可接受的转换)
//less 的 () 运算符重载函数,使用了 const 进行修饰 -- 常成员函数
//const 修饰的成员函数,只能调用 const 修饰的成员函数
//less 调用了 < 运算符函数,但是这里 没有使用 const 修饰
//--》解决办法: 使用 const 修饰这个 < 运算符重载
bool operator < (const AAA &A) const{
//比较 x 的大小,x 越小,AAA 越小
return x < A.x;
}
};
template<typename T>
class MyRule
{
public:
//函数 : 返回值 函数名 (参数表)
//运算符重载: 返回值 operator 运算符 (参数表)
bool operator () (const T& a, const T& b) const
{
//return a > b; //一般使用 < 运算符进行比较
return b < a;
}
};
bool MyComp(int a, int b)
{
return a > b;
}
bool MyCompA(const AAA &A1, const AAA& A2)
{
//return A1 > A2; // > 符号为定义,要不要重新定义的 > 符号?
// 不需要, 我们可以使用 A2 < A1
// 其次,也是很重要的一点:我们定义了 < 符号
// 那么,所有的比较规则,都已经定义好了
// 也就是说 > , >=, <=, ==, != 都可以有 < 符号表示出来
// 再定义一个容易出冲突: 比如出现 A != A , A1 < A2 < A1 这种情况
//注意 !(A1<A2) 和 A1>A2 是不等价的 !(A1<A2) 等价于 A1>=A2
return A2 < A1;
}
void TestPriorityQueue()
{
int arr[] = { 1, 3, 5, 7, 9, 8, 6, 4, 2, 0 };
priority_queue<int> iPriQue1;
priority_queue<int> iPriQue2(iPriQue1);
//关于底层容器:默认 使用 vector 做底层容器
//使用 list 作为底层容器, deque 作为底层容器 ?
priority_queue<int, deque<int>> iPriQue4;
//priority_queue<int, list<int>> iPriQue5;
//优先级队列,需要使用树形结构,设计到找父子节点,这个需要可以随机访问的容器
//list 不是随机访问容器,不能作为 priority_queue 的底层容器
cout << "入队列:" << endl;
//sizeof(arr): arr 总共占用多大空间
//sizeof(arr[0]): 一个元素占用多大空间
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){
cout << arr[i] << " ";
iPriQue1.push(arr[i]);
iPriQue4.push(i);
}
cout << endl;
//empty(): 判空
//size(): 当前容器中元素个数
cout << "出队列:" << endl;
while (!iPriQue1.empty()) {//while(iPriQue1.size())
cout << iPriQue1.top() << " "; //注意,取队头元素和 stack 类似,而不是和 queue 类似
//没有 front() 和 back()
iPriQue1.pop(); //删除优先级队列第一个元素
}
cout << endl;
while (!iPriQue4.empty()){
cout << iPriQue4.top() << " ";
iPriQue4.pop();
}
cout << endl << endl;
//出队列总是从大到小出队列
//优先级队列,会根据元素大小排序出队列 (先大后小)
//能不能先小后大呢? ---- 必然可以
/*
template<class _Ty,
class _Container = vector<_Ty>,
class _Pr = less<typename _Container::value_type> >
class priority_queue {};
//优先级队列有三个模板参数:
_Ty: 存储的元素类型
_Container: 底层容器,默认值是 vector<_Ty>
_Pr : 排序规则,默认是 less<_Ty>
*/
//less 是一个模板类 ,重载了 () 运算符 --》仿函数的类
//使用方式:比如判断 int a, b 的大小
int a = 10;
int b = 20;
less<int>()(a, b); //判断是否 a < b
//less --》 模板类
//less<int> --》 具体类
//less<int>() --》 生成一个对象 (匿名对象)
//less<int>()(a, b) --》调用这个对象的 () 运算符重载
//比如:class AAA --》 AAA() 生成一个 AAA类的对象
// --》 AAA(10,20) 生成一个 AAA 类的对象
//我们可以自己定义仿函数,替代 less<T>
//比如,写一个 MyRule 的类,里面重载 () 运算符,返回值和 less<T> 刚好相反
priority_queue<int, vector<int>, MyRule<int>> iPriQue3;
//注意,第三个模板参数,是变量类型(具体类),不是模板类。
// 对于模板类,需要实例化成具体类
cout << "iPriQue3" << endl;
cout << "入队列:" << endl;
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){
cout << arr[i] << " ";
iPriQue3.push(arr[i]);
}
cout << endl;
cout << "出队列: " << endl;
while (!iPriQue3.empty()){
cout << iPriQue3.top() << " ";
iPriQue3.pop();
}
cout << endl << endl;
//另一种方式定义排序规则: 使用函数指针: MyComp 函数
//MyComp 是一个函数指针变量
//他的变量类型是: 入参是 (int, int) 返回值是 bool 的函数
// --- bool(*)(int,int)
//把 MyComp 作为参数传入,作为 priority_queue 构造函数的入参
priority_queue<int, vector<int>, bool(*)(int, int)> iPriQue6(MyComp);
cout << "iPriQue6" << endl;
cout << "入队列:" << endl;
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){
cout << arr[i] << " ";
iPriQue6.push(arr[i]);
}
cout << endl;
cout << "出队列: " << endl;
while (!iPriQue6.empty()){
cout << iPriQue6.top() << " ";
iPriQue6.pop();
}
cout << endl << endl;
priority_queue<string> sPriQue;
string sArr[] = { string("aaa"), string("bbb"), string("cccc") };
sPriQue.push(sArr[2]);
//那么:如果优先级队列中存储的是自定义对象呢
// 比如上面的 AAA 对象
}
void TestAAA()
{
int a[] = { 1, 2, 3, 4, 5, 6 };
a[3];
AAA aArr[] = { AAA(), AAA(1, 2), AAA(2, 1), AAA(2, 2), AAA(1, 1), AAA(1, 3) };
//也有这种写法 AAA aArr[] = { {}, {1, 2}, {2, 1}, .... } --> {1,2} 相当于 AAA(1,2)
priority_queue<AAA> aPriQue1;
cout << "入队列:";
for (int i = 0; i < sizeof(aArr) / sizeof(aArr[0]); i++){
cout << aArr[i] << " ";
//二进制“<”:“const AAA”不定义该运算符或到预定义运算符可接收的类型的转换
//为什么插入 AAA 对象失败呢?
//优先级队列,会调用 less<AAA>()(A1, A2) 来比较 两个 AAA 对象的大小
// less 这个函数,return了 A1 < A2
// 但是, AAA 对象,不能做小于符号比较,所以报错:“<”未定义
//--》解决办法:重载 < 符号
aPriQue1.push(aArr[i]);
}
cout << endl;
cout << "出队列:";
while (!aPriQue1.empty()){
cout << aPriQue1.top() << " ";
aPriQue1.pop();
//根据比较规则,按照 x 的大小,从大到小输出
}
cout << endl << endl;
//如果,我们想把AAA对象, 从小到大输出?
priority_queue<AAA, vector<AAA>, bool(*)(const AAA&, const AAA&)> aPriQue2(MyCompA);
priority_queue<AAA, vector<AAA>, MyRule<AAA>> aPriQue3;
cout << "aPriQue2, aPriQue3" << endl;
cout << "入队列:";
for (int i = 0; i < sizeof(aArr) / sizeof(aArr[0]); i++){
cout << aArr[i] << " ";
aPriQue2.push(aArr[i]);
aPriQue3.push(aArr[i]);
}
cout << endl;
cout << "出队列:";
while (!aPriQue2.empty()){
cout << aPriQue2.top() << " ";
aPriQue2.pop();
//根据比较规则,按照 x 的大小,从大到小输出
}
cout << endl;
cout << "出队列:";
while (!aPriQue3.empty()){
cout << aPriQue3.top() << " ";
aPriQue3.pop();
//根据比较规则,按照 x 的大小,从大到小输出
}
cout << endl;
}
class BBB
{
private:
int x;
public:
friend class MyRuleB;
BBB(int a) :x(a){}
};
class MyRuleB
{
public:
bool operator () (const BBB &B1, const BBB &B2) const
{
return B1.x < B2.x;
}
};
void TestBBB()
{
//BBB(1) --》 调用 BBB 的构造函数 BBB(int a) 生成一个 BBB 的对象
//BBB 是一个类,就是一个变量类型,用于定义变量(对象)
// int a; char b; BBB B;
// 对象里面包含私有成员,我们定义构造函数,来初始化这些成员 BBB(int a):x(a){}
// 那么 BBB B(1) ---> 调用构造函数 BBB(int a) 把 x 赋值为 1
// ---> 也就是说 B 这个对象,他的私有成员 x 的值是 1
// BBB(1) ---> 直接类名后加(), 表示调用相应的构造函数,生成一个匿名对象
// 或者说,我们可以进行赋值 BBB B = BBB(1)
// 类似于 string("AAA"); string ss = string("Hello");
BBB bArr[] = { BBB(1), BBB(3), BBB(2), BBB(4) };
priority_queue<BBB, vector<BBB>, MyRuleB> bPriQue;
//我们也可以不重载 < 符号,定义优先级队列的时候,直接传入 比较规则
//但是这样写有个问题:比较规则需要定义成 BBB 的友元类,用于访问 BBB 的 私有成员
// 友元类存在安全性问题,在类中可以修改它的私有成员
//当然,我们不想定义友元类也行,需要 写成员函数,返回 x 的值
// BBB::getVal(){return x;} --> 写法比较麻烦,而且私有成员没有隐藏
//一般情况下,还是建议重载 < 运算符 (使用 AAA 的做法)
for (int i = 0; i < sizeof(bArr) / sizeof(bArr[0]); i++){
bPriQue.push(bArr[i]);
}
}
int main()
{
//TestPriorityQueue();
TestAAA();
TestBBB();
system("pause");
return 0;
}
//作业:
//定义 4 个优先级队列,存储string对象 {"AA", "BBBB", "CCC", "aaaa", "cc", "bbb"}
//要求:
//sPriQue1: 出队列的时候,按照字符串 ASCII 降序排列
//sPriQue2: 出队列的时候,按照字符串 ASCII 升序排列
//sPriQue3: 出队列的时候,按照字符串长度 升序排列(长度一样再比较 ASCII 升序)
//sPriQue4: 出队列的时候,按照字符串长度 降序排列(长度一样再比较 ASCII 降序)