priority_queue
优先队列(priority_queue)也是队列的一种,priority_queue的接口是和queue的接口是相同的。所以两者的使用语法也是相同的。我们直接看优先队列(priority——queue)的底层实现原理。
默认情况下priority_queue是大堆。
priority_queue 使用
//用vector作为底层容器,内部构造大堆结构。
priority_queue<int, vector<int>, less<int>> q1;
//用vector作为底层容器,内部构造小堆结构。
priority_queue<int, vector<int>, greater<int>> q2;
//不指定底层容器和内部需要构造的堆结构。
priority_queue<int> q3;
#include <iostream>
#include <functional>
#include <queue>
using namespace std;
int main()
{
priority_queue<int> q;
q.push(3);
q.push(6);
q.push(0);
q.push(2);
q.push(9);
q.push(8);
q.push(1);
while (!q.empty())
{
cout << q.top() << " ";
q.pop();
}
cout << endl; //9 8 6 3 2 1 0
return 0;
}
priority_queue的模拟实现
priority_queue的底层实际上就是堆,模拟实现priority_queue之前,需要知道向下调整和向上调整算法。(下面这两种算法我们均以大堆为例)
向上调整算法
向上调整算法的前提:
若想将其调整为小堆,那么根结点的左右子树必须都为小堆。
若想将其调整为大堆,那么根结点的左右子树必须都为大堆
向堆中插入数据需要使用到向上调整算法
先将元素插入到堆的末尾,即最后一个孩子之后,从插入节点位置开始和父节点比较,(我们以大堆为例),如果目标结点的值比父结点的值大,则交换目标结点与其父结点的位置,并将原目标节点的父节点当作新的目标节点,继续向上调整,调整到根节点结束,此时该树已经是大堆了
图中是以小堆为例:
向下调整算法
向下调整算法的前提:
若想将其调整为小堆,那么根结点的左右子树必须都为小堆。
若想将其调整为大堆,那么根结点的左右子树必须都为大堆
从根节点开始,选出左右孩子值较大的节点,让值较大的节点与父节点的值进行比较,如果值较大的节点比父节点的值小,交换两者位置,将原来值较大的孩子节点作为父节点,继续向下调整,调整到叶子节点结束
图中是以小堆为例:
push
void push(const T & x)
{
_con.push_back(x);
AdjustUp(_con.size() - 1);
}
pop
void pop()
{
swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
AdjustDown(0);
}
top
const T& top()
{
return _con[0];
}
size
bool size()
{
return _con.size();
}
empty
bool empty()
{
return _con.empty();
}
仿函数
using namespace std;
//仿函数 /函数对象
template <class T>
class Less
{
public:
bool operator() (const T& x, const T& y)
{
return x < y;
}
};
int main()
{
Less<int> lessfunc;
bool result = lessfunc(6, 2);//仿函数
//bool result = lessfunc.operator()(6, 2);
cout <<boolalpha <<result << endl;
return 0;
}
完整代码
#pragma once
#include<vector>
#include<functional>
using namespace std;
//仿函数 /函数对象
template <class T>
class Less
{
public:
bool operator() (const T& x, const T& y)
{
return x < y;
}
};
template <class T>
class Greater
{
public:
bool operator() (const T& x, const T& y)
{
return x > y;
}
};
namespace cxq
{
template<class T, class Container = vector<T>, class Compare = Less<T> >
class priority_queue
{
private:
void AdjustDown(int parent)//从根节点开始
{
Compare com;//仿函数
int child = parent * 2 + 1;
while (child < _con.size())
{
//假设默认左孩子大于右孩子
// if (child + 1 < _con.size() && _con[child + 1] > _con[child])//右孩子要存在,防止越界
if (child + 1 < _con.size() && com(_con[child + 1], _con[child]))
{
child++;
}
//if (_con[child] > _con[parent])
if (com(_con[parent], _con[child]))
{
swap(_con[child], _con[parent]);
int parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void AdjustUp(int child)
{
Compare com;//仿函数
int parent = (child - 1) / 2;
//大堆
while (child > 0)
{
//if (_con[child] > _con[parent])
if (com(_con[parent], _con[child]))
{
swap(_con[child], _con[parent]);
int child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
public:
//默认构造
priority_queue()
{}
template<class InputIterator>
//构造函数
priority_queue(InputIterator first, InputIterator last)
{
while (first != last)
{
_con.push_back(*first);
first++;
}
//建堆
//最后一个非叶子节点
for (size_t i = (_con.size() - 1 - 1) / 2; i >= 0; i++)
{
AdjustDown(i);
}
}
void pop()
{
swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
AdjustDown(0);
}
void push(const T& x)
{
_con.push_back(x);
AdjustUp(_con.size() - 1);
}
const T& top()
{
return _con[0];
}
bool empty()
{
return _con.empty();
}
bool size()
{
return _con.size();
}
private:
Container _con;
};
void test_priority_queue1()
{
//默认是大堆--less
//priority_queue<int> pq;
priority_queue<int, vector<int>, Greater<int> > pq;//小堆
pq.push(3);
pq.push(5);
pq.push(1);
pq.push(4);
while (!pq.empty())
{
cout << pq.top() << " ";
pq.pop();
}
cout << endl;
}
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;
}
struct LessPDate
{
//仿函数
bool operator() ( const Date * p1 , const Date* p2)
{
return *p1 < *p2;
}
};
void test_priority_queue2()
{
//priority_queue<Date> pq;
//pq.push(Date(2023, 7, 20));
//pq.push(Date(2023, 6, 20));
//pq.push(Date(2023, 8, 20));
//while (!pq.empty())
//{
// cout << pq.top() << " ";
// pq.pop();
//}
//cout << endl;
priority_queue<Date*, vector<Date*>, LessPDate> pq;
pq.push(new Date(2023, 7, 20));
pq.push(new Date(2023, 6, 20));
pq.push(new Date(2023, 8, 20));
while (!pq.empty())
{
cout << *pq.top() << " ";
pq.pop();
}
cout << endl;
}
}