优先队列
- 一.基本使用
- 二.模拟实现
- 三.仿函数
- 1.优先队列里的使用
- 2.概念
- 3.模拟
一.基本使用
优先队列的底层默认是使用vector构造的,也就是使用数组模拟(二叉树)堆。并且默认是按大堆存放数据(也就是父节点>子节点,左节点>右节点)。
优先队列的成员函数不多,常用的就是empty,size,top,pop,push。
简单使用
首先优先队列常使用区间初始化和无参初始化。
可以使用push插入数据,注意因为优先队列是使用数组模拟堆,所以不能直接遍历。只能通过不断访问顶部数据,再不断弹出顶部数据进行间接遍历。
二.模拟实现
这里使用了模板参数(template<class T,class Container=vector>),一共有两个参数,第一个T用来适配不同类型的数据(例如int,string或者自定义类型),第二个参数默认是vector,也就是底层默认是用vector实现优先队列,当然也可以使用list等等(这里与库里保持一致)。
#include<vector>
namespace mine
{
template<class T,class Container=vector<T>>
class priority_queue
{
private:
//向下调整
void AdjustDown(int parent)
{
int child = parent * 2 + 1;
while (child < _con.size())
{
if (child + 1 < _con.size() && _con[child]< _con[child + 1])
{
child++;
}
if (_con[parent]<_con[child])
{
swap(_con[child], _con[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
//向上调整
void AdjustUp(int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (_con[parent] <_con[child])
{
swap(_con[child], _con[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
public:
//无参构造
priority_queue()
{}
//区间构造
template<class InputLterater>
priority_queue(InputLterater first,InputLterater last)
{
while (first != last)
{
_con.push_back(*first);
first++;
}
for (int 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];
}
//数组大小
size_t size()
{
return _con.size();
}
//是否为空
bool empty()
{
return _con.empty();
}
private:
Container _con;
};
}
测试
#include<iostream>
using namespace std;
#include"priority_queue.h"
int main()
{
int a[9] = { 4,8,1,9,6,7,2,5,5};
mine::priority_queue<int> v(a,a+9);//使用区间初始化
mine::priority_queue<int> vv;//无参初始化
vv.push(5);
vv.push(2);
vv.push(7);
vv.push(11);
while (!vv.empty())
{
cout << vv.top() << ' ';
vv.pop();
}
return 0;
}
三.仿函数
1.优先队列里的使用
在库里除了T,Container两个模板参数外,还有一个Compare参数,这是一个仿函数用来改变存储顺序(默认是less,也就是大堆,可以改成greater,也就是小堆)
2.概念
仿函数的底层实际很简单,就是一个类里面重载了一个括号()运算符。
仿函数的本质就是一个类的对象可以像函数一样使用。
3.模拟
由于less,greater本质都是类,库里有实现,所以就可以直接使用。
#include<vector>
namespace mine
{
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 (com(child + 1, _con.size()) && com( _con[child], _con[child + 1]))
{
child++;
}
if (com(_con[parent],_con[child]))
{
swap(_con[child], _con[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
//向上调整
void AdjustUp(int child)
{
Compare com;
int parent = (child - 1) / 2;
while (child > 0)
{
if (com(_con[parent],_con[child]))
{
swap(_con[child], _con[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
public:
//无参构造
priority_queue()
{}
//区间构造
template<class InputLterater>
priority_queue(InputLterater first,InputLterater last)
{
while (first != last)
{
_con.push_back(*first);
first++;
}
for (int 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];
}
//数组大小
size_t size()
{
return _con.size();
}
//是否为空
bool empty()
{
return _con.empty();
}
private:
Container _con;
};
}