好多天没有更新博客了,最近一直在忙着学linux和自己的专业课(因为博主不是科班的~)。现在在学校感觉时间有些紧,等到期末考完了,博主就全身心把linux博客总结并分享给大家~
优先级队列也是STL库中非常实用的一个容器。底层实现和堆很相似,这个容器又和之前讲的string、vector、list...模板参数上有些区别,今天来和老铁们一起见识一下这个容器~
目录
priority_queue(InputIterator first, InputIterator last)
priority_queue的介绍
我们先来看一下C++文档的介绍:
我们翻译成中文:
priority_queue的使用
construct
priority_queue()
举个栗子:
#include<iostream>
#include<functional>
#include<queue>
using namespace std;
int main()
{
/*explicit priority_queue(const Compare & comp =Compare(),
const Container & ctnr = Container()); */
priority_queue<int> q;
return 0;
}
我们调试一下看看情况:
priority_queue(first, last)
举个栗子:
int main()
{
/*template <class InputIterator>
priority_queue (InputIterator first, InputIterator last,
const Compare& comp = Compare(),
const Container& ctnr = Container());*/
//传vector迭代器
vector<int> v = { 1,2,3,4,5 }; //C++11支持的语法
priority_queue<int> q1(v.begin(),v.end());
//传list迭代器
list<int> l = { 10,20,30,40,50 };//C++11支持的语法
priority_queue<int> q2(l.begin(), l.end());
//普通数组
int arr[] = { 5,4,3,2,1 };
priority_queue<int> q3(arr, arr + 5);
return 0;
}
我们调试一下看看情况:
我们在上面看到了它有三个模板参数,那么我们应该怎么把控呢?
举个栗子:
int main()
{
vector<int> v1 = { 1,2,3,4,5 };
priority_queue<int, vector<int>, greater<int>> q1(v1.begin(), v1.end());
vector<int> v2 = { 50,40,30,20,10 };
priority_queue<int, deque<int>, greater<int>> q2(v2.begin(), v2.end());
return 0;
}
我们调试一下看看情况:
empty()
举个栗子:
int main()
{
priority_queue<int> q1;
cout << q1.empty() << endl;
vector<int> v = { 1,2,3,4,5 };
priority_queue<int> q2(v.begin(), v.end());
cout << q2.empty() << endl;
return 0;
}
运行结果:
top()
举个栗子:
int main()
{
vector<int> v = { 1,2,3,4,5 };
priority_queue<int> q(v.begin(), v.end()); //默认是建大堆
cout << q.top() << endl;
return 0;
}
运行结果:
push()
举个栗子:
int main()
{
priority_queue<int> q;
q.push(1);
q.push(2);
q.push(5);
q.push(4);
q.push(3);
return 0;
}
我们来调试一下看看情况:
pop()
举个栗子:
int main()
{
priority_queue<int> q;
q.push(1);
q.push(2);
q.push(5);
q.push(4);
q.push(3);
q.pop();
return 0;
}
我们调试一下来看看情况:
size()
举个栗子:
int main()
{
priority_queue<int> q;
q.push(1);
q.push(2);
q.push(3);
cout << q.size() << endl;
return 0;
}
运行结果:
swap()
举个栗子:
int main()
{
priority_queue<int> q1;
q1.push(5);
q1.push(4);
q1.push(3);
q1.push(2);
q1.push(1);
priority_queue<int> q2;
q2.push(50);
q2.push(40);
q2.push(30);
q2.push(20);
q2.push(10);
q1.swap(q2);
return 0;
}
我们来调试一下看看情况:
priority_queue模拟实现
Compare仿函数实现
less
//仿函数
template<class T>
struct less //大堆
{
bool operator()(const T& x, const T& y) const
{
return x < y;
}
};
//特化 -- 针对比如日期类这样的自定义类型 ->new出来的Date对象走这个
template<>
struct less<Date*>
{
bool operator()(const Date*& x, const Date*& y)const
{
return *x < *y;
}
};
greater
template<class T>
struct greater
{
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
//特化 -- 针对比如日期类这样的自定义类型 ->new出来的Date对象走这个
template<>
struct greater<Date*>
{
bool operator()(const Date*& x, const Date*& y) const
{
return *x > *y;
}
};
priority_queue()
//无参的构造函数
priority_queue()
{}
priority_queue(InputIterator first, InputIterator last)
template<class InputIterator>
priority_queue(InputIterator first, InputIterator last)
:_con(first, last) //先把数据录入_con中,实际上调用了_con的构造函数
{
//建堆
for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--)
{
adjust_down(i);
}
}
void adjust_down(int parent)
void adjust_down(int parent)
{
Compare com;//仿函数对象
int child = parent * 2 + 1;//默认是左孩子
while (child < _con.size()) //_con.size()-1的位置就是最后一个数据下标的位置了。child == _con.size()就会越界!
{
//if (child + 1 < _con.size() && _con[child + 1] > _con[child])
if (child + 1 < _con.size() && com(_con[child], _con[child+1]))
{
child += 1;
}
if (com(_con[parent], _con[child]))
{
swap(_con[parent], _con[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void push(const T& x)
void push(const T& x)
{
_con.push_back(x);
adjust_up(_con.size() - 1);//插入的数据向上调整
}
void adjust_up(int child)
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;
}
}
}
void pop()
void pop()
{
swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
adjust_down(0);
}
const T& top() const
const T& top() const
{
return _con[0];
}
size_t size()
size_t size()
{
return _con.size();
}
bool empty()
bool empty()
{
return _con.empty();
}
完整代码
priority_queue.h
#pragma once
#include<iostream>
#include"Date.h"
#include<vector>
#include<deque>
#include<algorithm>
using namespace std;
namespace cyq
{
//仿函数
template<class T>
struct less //大堆
{
bool operator()(const T& x, const T& y) const
{
return x < y;
}
};
//特化 -- 针对比如日期类这样的自定义类型 ->new出来的Date对象走这个
template<>
struct less<Date*>
{
bool operator()(const Date*& x, const Date*& y)const
{
return *x < *y;
}
};
template<class T>
struct greater
{
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
//特化 -- 针对比如日期类这样的自定义类型 ->new出来的Date对象走这个
template<>
struct greater<Date*>
{
bool operator()(const Date*& x, const Date*& y) const
{
return *x > *y;
}
};
template<class T,class Container=vector<T>,class Compare=less<T>>
class priority_queue
{
private:
void adjust_down(int parent)
{
Compare com;//仿函数对象
int child = parent * 2 + 1;//默认是左孩子
while (child < _con.size()) //_con.size()-1的位置就是最后一个数据下标的位置了。child == _con.size()就会越界!
{
//if (child + 1 < _con.size() && _con[child + 1] > _con[child])
if (child + 1 < _con.size() && com(_con[child], _con[child+1]))
{
child += 1;
}
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:
//无参的构造函数
priority_queue()
{}
template<class InputIterator>
priority_queue(InputIterator first, InputIterator last)
:_con(first, last) //先把数据录入_con中,实际上调用了_con的构造函数
{
//建堆
for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--)
{
adjust_down(i);
}
}
void push(const T& x)
{
_con.push_back(x);
adjust_up(_con.size() - 1);//插入的数据向上调整
}
void pop()
{
swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
adjust_down(0);
}
const T& top() const
{
return _con[0];
}
size_t size()
{
return _con.size();
}
bool empty()
{
return _con.empty();
}
private:
Container _con;
};
}
Date.h
#pragma once
#include<iostream>
using namespace std;
class Date
{
friend ostream& operator<<(ostream& out, const Date& d);
public:
Date(int year=1,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);
}
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "-" << d._month << "-" << d._day;
return out;
}
测试代码
int main()
{
cyq::priority_queue<int> q1;
q1.push(1);
q1.push(2);
q1.push(3);
q1.push(4);
q1.push(5);
vector<int> v = { 50,40,30,20,10 };
cyq::priority_queue<int> q2(v.begin(), v.end());
q2.pop();
cout << q2.top() << endl;
cyq::priority_queue<int,vector<int>,greater<int>> q4;
q4.push(5);
q4.push(4);
q4.push(3);
q4.push(2);
q4.push(1);
cyq::priority_queue<Date> q3;
q3.push(Date(2022, 4, 31));
q3.push(Date(2022, 5, 1));
q3.push(Date(2021, 5, 1));
q3.push(Date(2021, 4, 31));
return 0;
}
通过调试窗口来看:
总结
如果老铁们还想进一步了解堆这个算法可以看看博主曾经花了2天写的博客:
常见排序算法激烈讲解_暴走的橙子~的博客-CSDN博客
注意
看下面的代码:
cyq::priority_queue<Date*,vector<Date*>,cyq::greater<Date*>> q3;
q3.push(new Date(2022, 4, 31));
q3.push(new Date(2022, 5, 1));
q3.push(new Date(2021, 5, 1));
q3.push(new Date(2021, 4, 31));
q3.push(new Date(2021, 6, 31));
q3.push(new Date(2022, 5, 31));
while (!q3.empty())
{
cout << *(q3.top()) << endl;
q3.pop();
}
我们把new出来的对象的地址放进优先级队列。再看看我们实现的push版本:
void push(const T& x)
{
_con.push_back(x);
adjust_up(_con.size() - 1);//插入的数据向上调整
}
运行结果:
看到这里给博主支持下吧~