一.什么是priority_queue(优先级队列)
优先级队列是一种容器适配器,数据的存储是采用堆的形式实现的,保证第一个元素是优先级队列的最大值或最小值。(默认建大堆)
默认用vector作为底层数据的存储容器。
二.priority_queue的三个类模板参数
1.class T
T是优先级队列中存储元素的类型
2.class Container = vector<T>
Container是优先队列底层使用的存储结构(默认用vector)
3.class Compare = less<typename Container::value_type>
Compare是定义元素比较的方式。(默认less建大堆)
为什么根据Compare可以对元素进行比较呢?
首先我们要了解什么是仿函数。
仿函数
仿函数实际上是一个类的对象,通过operator() 运算符重载来模拟函数调用的过程。
可以利用模板对不同元素进行比较。
因为要建小堆或者大堆,比较方式会不同。就需要Compare接收不同的类来改变比较方式。
template<class T>
class less
{
public:
bool operator()(T a, T b)
{
return a < b;
}
};
template<class T>
class greater
{
public:
bool operator()(T a, T b)
{
return a > b;
}
};
template<class T, class Container = vector<T>,class Compare=less<T>>
class PriorityQueue
{
public:
PriorityQueue() = default;//强制生成默认构造
template <class InputIterator>
PriorityQueue(InputIterator first, InputIterator last)
{
while (first != last)
{
c.push_back(*first);
first++;
}
size_t parent = (c.size() - 1 - 1) / 2;
while (parent > 0)
{
size_t child = parent * 2 + 1;
if (child + 1 < c.size() && comp(c[child], c[child + 1]))
{
child++;
}
if (c[parent] < c[child]) swap(c[parent], c[child]);
parent--;
}
}
private:
Container c;
Compare comp;
};
}
建大堆就传入less类,小堆就传入greater类
自定义类型比较
如果优先级队列中存入的是自定义类型,那应该怎么进行比较呢?
这就需要我们在自定义类型的类中重载大于> 小于< 。这样在less greater类的函数中就可以对><进行重载,实现大小的比较。
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);
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
_cout << d._year << "-" << d._month << "-" << d._day;
return _cout;
}
但如果我要存入Date对象的地址呢?
less greater类中函数直接比较的就是地址的大小。那我们可以新建一个类,先对地址解引用,在利用函数重载进行比较。
struct PDateLess
{
bool operator()(Date* p1, Date* p2)
{
return *p1 < *p2;
}
};
struct PDateGreater
{
bool operator()(Date* p1, Date* p2)
{
return *p1 > *p2;
}
};
void TestPriorityQueue()
{
// 大堆,需要用户在自定义类型中提供<的重载
wws::PriorityQueue<Date*, vector<Date*>, PDateLess> q1;
q1.push(new Date(2024, 6, 1));
q1.push(new Date(2024, 6, 2));
q1.push(new Date(2024, 6, 3));
while (!q1.empty())
{
cout << *q1.top() << " ";
q1.pop();
}
cout << endl;
}
三.priority_queue模拟实现
#pragma once
#include<iostream>
using namespace std;
#include<vector>
namespace wws
{
template<class T>
class less
{
public:
bool operator()(T a, T b)
{
return a < b;
}
};
template<class T>
class greater
{
public:
bool operator()(T a, T b)
{
return a > b;
}
};
template<class T, class Container = vector<T>,class Compare=less<T>>
class PriorityQueue
{
public:
PriorityQueue() = default;//强制生成默认构造
template <class InputIterator>
PriorityQueue(InputIterator first, InputIterator last)
{
while (first != last)
{
c.push_back(*first);
first++;
}
size_t parent = (c.size() - 1 - 1) / 2;
while (parent > 0)
{
size_t child = parent * 2 + 1;
if (child + 1 < c.size() && comp(c[child], c[child + 1]))
{
child++;
}
if (c[parent] < c[child]) swap(c[parent], c[child]);
parent--;
}
}
void push(const T& x)
{
c.push_back(x);
size_t child = c.size() - 1;
while (child > 0)
{
size_t parent = (child - 1) / 2;
if (comp(c[parent] , c[child]))
{
swap(c[parent], c[child]);
child = parent;
}
else break;
}
}
void pop()
{
swap(c[0], c[(c.size() - 1)]);
c.pop_back();
size_t parent = 0, child = parent * 2 + 1;
while (child<c.size())
{
if (child + 1 < c.size() && comp(c[child], c[child+1]))
{
child++;
}
if (comp(c[parent], c[child]))
{
swap(c[parent], c[child]);
parent = child;
child = parent * 2 + 1;
}
else break;
}
}
bool empty() const
{
return c.empty();
}
size_t size() const
{
return c.size();
}
const T& top() const
{
return c.front();
}
private:
Container c;
Compare comp;
};
}