函数声明 | 接口说明 |
---|---|
priority_queue()/priority_queue(first,last) | 构造一个空优先级队列/迭代器构造优先级队列 |
empty( ) | 检测优先级队列是否为空,是返回true,否则返回false |
top( ) | 返回优先级队列中最大(最小元素),即堆顶元素 |
push(x) | 在优先级队列中插入元素x |
pop() | 删除优先级队列中最大(最小)元素,即堆顶元素 |
#include
using namespace std;
void test()
{
priority_queue<int> pq;
pq.push(4);
pq.push(1);
pq.push(7);
pq.push(9);
cout << pq.top() << endl;
}
优先级队列的底层逻辑就是堆排序,在类模板中会有一个默认的模板参数也叫仿函数——less,默认是大的优先级高,想要控制小的优先级需要给一个——“greater” ,代表小的优先级高
template<class T,class Container = vector<T>>
class priority_queue
{
public:
priority_queue()
{}
private:
Container _con;
};
因为这里的成员函数类型是自定义类型,而自定义类型会去调用他自己的拷贝构造、析构、赋值重载等等,所以这里就不用写了
void adjust_up(size_t child)
{
size_t parent = (child-1)/2;
while(child)
{
if(_con[child] > _con[parent])
{
swap(_con[child],_con[parent]);
child = parent;
parent = (child-1)/2;
}
else
break;
}
}
void push(const T& val)
{
_con.push_back(val);
adjust_up(_con.size() - 1);
}
前面介绍过,优先级队列在默认情况下是个 “大堆”,而堆的push是向上调整,所以这里用的也是向上调整
void adjust_down(size_t parent)
{
size_t child = parent*2 + 1;
while(child < _con.size())
{
if(child+1 < _con.size() && _con[child+1] > con[child])
child++;
if(_con[child] > _con[parent])
{
swap(_con[child],_con[parent])
parent = child;
child = parent*2 + 1;
}
else
break;
}
}
void pop()
{
assert(!_con.empty());
swap(_con[0],_con[_con.size() - 1]);
_con.pop_back();
adjust_down(0);
}
堆的删除,删除最值的元素,也就是堆顶的元素(下标0的位置),先交换头部与尾部的数据,在删除尾部,最后向下调整
const T& top()
{
return _con.[0];
}
取最值,也就是堆顶的值
bool empty()
{
return _con.empty();
}
size_t size()
{
return _con.size();
}
template<class InputIterator>
priority_queue(InputIterator first,InputIterator last)
:_con(first,last) //vector是支持迭代器初始化的
{
//还需要把数组建成堆
for(int i = (_con.size() -1 -1)/2 ; i >= 0;i--)
{
adjust_down(i);
}
}
或者不使用初始化列表,直接用自己的push
while(first != last)
{
push(*first);
++first;
}
使用迭代器构造函数,需要把数组变为堆的结构,可以使用向下或者向下调整,向上调整就需要从第一个开始,每个数据都需要调整;向下调整则需要从最后一个叶子的父类节点开始直到0下标位置的元素,并每次都向下调整,因为向下调整的前提是左右两子树必须是堆(也可以复用上面的push函数,从0开始)
仿函数的定义和使用方法
struct Less
{
bool operator()(int x,int y)
{
return x < y;
}
};
struct Greater
{
bool operator()(int x, int y)
{
return x > y;
}
};
int main()
{
Less min;
Greater max;
cout << min(3,6) << endl;
cout << max(3,6) << endl;
return 0;
}
Less、Greater称作仿函数类型,max、min就是函数对象
可以看出,仿函数重载的是括号表达式,可以让对象像函数名一样调用使用(也可以用函数指针,但是太麻烦,所以C++设计了这种)
那么在priority_queue中的该如何定义? 请看如下代码:
template<class T>
struct Less
{
bool operator()(const T& x, const T& y)const
{
return x < y;
}
};
template<class T>
struct Greater
{
bool operator()(const T& x, const T& y)const
{
return x > y;
}
};
Greater和Less都是类型,那么类型就可以放到模板中去使用,所以:
template<class T,class Container = vector<T>, class Compare = Less<T>>
class priority_queue
{
......
......
void adjust_up(size_t child)
{
size_t parent = (child-1)/2;
while(child)
{
Compare com;
//if(_con[child] > _con[parent])
if( com(_con[parent] , _con[child]) )
{
swap(_con[child],_con[parent]);
child = parent;
parent = (child-1)/2;
}
else
break;
}
}
......
......
......
......
void adjust_down(size_t parent)
{
size_t child = parent*2 + 1;
while(child < _con.size())
{
Compare com;
//if(child+1 < _con.size() && _con[child+1] > con[child])
if(child+1 < _con.size() && com(_con[child] , con[child+1]) )
child++;
//if(_con[child] > _con[parent])
if( com(_con[parent] , _con[child]) )
{
swap(_con[child],_con[parent])
parent = child;
child = parent*2 + 1;
}
else
break;
}
}
......
......
};
priority_queue默认是Less(大的优先),想设置小的优先,参数传Greater就可以
整体代码:
template<class T>
struct Less
{
bool operator()(const T& x, const T& y)const
{
return x < y;
}
};
template<class T>
struct Greater
{
bool operator()(const T& x, const T& y)const
{
return x > y;
}
};
template<class T,class Container = vector<T>, class Compare = Less<T>>
class priority_queue
{
public:
priority_queue()
{}
template<class InputIterator>
priority_queue(InputIterator first,InputIterator last)
:_con(first,last)
{
for(int i = (_con.size() -1 -1)/2 ; i >= 0;i--)
{
adjust_down(i);
}
}
void push(const T& val)
{
_con.push_back(val);
adjust_up(_con.size() - 1);
}
void pop()
{
assert(!_con.empty());
swap(_con[0],_con[_con.size() - 1]);
_con.pop_back();
adjust_down(0);
}
const T& top()
{
return _con[0];
}
bool empty()
{
return _con.empty();
}
size_t size()
{
return _con.size();
}
private:
void adjust_down(size_t parent)
{
size_t child = parent*2 + 1;
while(child < _con.size())
{
Compare com;
//if(child+1 < _con.size() && _con[child+1] > con[child])
if(child+1 < _con.size() && com(_con[child] , con[child+1]) )
child++;
//if(_con[child] > _con[parent])
if( com(_con[parent] , _con[child]) )
{
swap(_con[child],_con[parent])
parent = child;
child = parent*2 + 1;
}
else
break;
}
}
void adjust_up(size_t child)
{
size_t parent = (child-1)/2;
while(child)
{
Compare com;
//if(_con[child] > _con[parent])
if( com(_con[parent] , _con[child]) )
{
swap(_con[child],_con[parent]);
child = parent;
parent = (child-1)/2;
}
else
break;
}
}
private:
Container _con;
};