priority_queue的介绍
priority_queue的使用事项
优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成 堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。
注意:
1.默认情况下priority_queue是大堆。
#include <vector>
#include <queue>
#include <functional> // greater算法的头文件
void TestPriorityQueue()
{
// 默认情况下,创建的是大堆,其底层按照小于号比较
vector<int> v{3,2,7,6,0,4,1,9,8,5};
priority_queue<int> q1;
for (auto& e : v)
q1.push(e);
cout << q1.top() << endl;
// 如果要创建小堆,将第三个模板参数换成greater比较方式
priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());
cout << q2.top() << endl;
}
2.(重要) 如果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;
};
void TestPriorityQueue()
{
// 大堆,需要用户在自定义类型中提供<的重载
priority_queue<Date> q1;
q1.push(Date(2018, 10, 29));
q1.push(Date(2018, 10, 28));
q1.push(Date(2018, 10, 30));
cout << q1.top() << endl;
// 如果要创建小堆,需要用户提供>的重载
priority_queue<Date, vector<Date>, greater<Date>> q2;
q2.push(Date(2018, 10, 29));
q2.push(Date(2018, 10, 28));
q2.push(Date(2018, 10, 30));
cout << q2.top() << endl;
}
priority_queue的模板(重要)
模拟实现priority_queue时,需要知道priority_queue的模板是什么,priority_queue的模板参数包含三个:
-
T(Type):这是优先队列中存储的元素类型。你可以在优先队列中存储任何 C++ 数据类型的元素,例如整数、浮点数、自定义结构或类等。这是
std::priority_queue
的必选模板参数。 -
Container:这是用来存储元素的底层容器类型。默认情况下,
std::priority_queue
使用std::vector<T>
作为底层容器来存储元素。也就是说,如果你不提供第二个模板参数,std::priority_queue
将使用std::vector
作为底层容器。你可以根据需要选择不同的容器类型,例如std::deque
、std::list
等,以满足特定的性能需求。如果你要指定一个不同的容器类型,需要提供它作为第二个模板参数。 -
Compare:这是一个可选参数,用于比较元素的优先级。默认情况下,如果不提供第三个模板参数,
std::priority_queue
将使用std::less<T>
作为比较函数,创建最大堆。如果你希望创建最小堆,可以提供std::greater<T>
作为比较函数。你还可以自定义一个比较函数,以根据自己的优先级规则来排序元素。
template<class T, class Container, class Compare>
priority_queue的模拟实现(代码)
template<class T>
struct less //大堆
{
bool operator()(const T& left, const T& right)
{
return left < right;
}
};
template<class T>
struct greater //小堆
{
bool operator()(const T& left, const T& right)
{
return left > right;
}
};
template<class T, class Container = std::vector<T>, class Compare = less<T>>
class priority_queue
{
public:
// 创造空的优先级队列
priority_queue() : c() {}
template<class Iterator>
priority_queue(Iterator first, Iterator last)
: c(first, last)
{
// 将c中的元素调整成堆的结构
int count = c.size();
int root = ((count - 2) >> 1);
for (; root >= 0; root--)
AdjustDown(root);
}
void push(const T& data)
{
c.push_back(data);
AdjustUP(c.size() - 1);
}
void pop()
{
if (empty())
return;
swap(c.front(), c.back());
c.pop_back();
AdjustDown(0);
}
size_t size()const
{
return c.size();
}
bool empty()const
{
return c.empty();
}
// 堆顶元素不允许修改,因为:堆顶元素修改可以会破坏堆的特性
const T& top()const
{
return c.front();
}
private:
// 向上调整
void AdjustUP(int child)
{
int parent = ((child - 1) >> 1);
while (child)
{
if (Compare()(c[parent], c[child]))
{
swap(c[child], c[parent]);
child = parent;
parent = ((child - 1) >> 1);
}
else
{
return;
}
}
}
// 向下调整
void AdjustDown(int parent)
{
size_t child = parent * 2 + 1;
while (child < c.size())
{
// 找以parent为根的较大的孩子
if (child + 1 < c.size() && Compare()(c[child], c[child + 1]))
child += 1;
// 检测双亲是否满足情况
if (Compare()(c[parent], c[child]))
{
swap(c[child], c[parent]);
parent = child;
child = parent * 2 + 1;
}
else
return;
}
}
private:
Container c;
};