前言
在上一小节中,我们分析了heap
算法,其实是为了priority_queue
优先级队列做准备,它也不是容器,而是配接器,因为它是通过vector
来实现的,然后封装了一些vector
提供的接口供自己使用而形成的。
优先级队列,即一种特殊的队列,但是它内部的元素没有按照传统队列的先进先出这种顺序排序,而是按照元素的权值进行排列,所以执行出队操作时,出队的是权值最大的元素。
priority_queue
在SGISTL的实现中,priority_queue
队列底部实现的容器就是vector
,然后再配合heap
提供的一些算法就可以完成优先级队列的所有功能了。
它的实现源码如下:
定义部分
#ifndef __STL_LIMITED_DEFAULT_TEMPLATES
template <class T, class Sequence = vector<T>,
class Compare = less<typename Sequence::value_type> >
#else
template <class T, class Sequence, class Compare>
#endif
class priority_queue {
public:
//定义的一些常用的类型
typedef typename Sequence::value_type value_type;
typedef typename Sequence::size_type size_type;
typedef typename Sequence::reference reference;
typedef typename Sequence::const_reference const_reference;
protected:
//底部容器
Sequence c;
//比较大小的标准
Compare comp;
构造函数
public:
//默认构造函数,只构造一个空的容器
priority_queue() : c() {}
//防止隐式转换
explicit priority_queue(const Compare& x) : c(), comp(x) {}
#ifdef __STL_MEMBER_TEMPLATES
//以迭代器范围构造时,调用make_heap函数使这些元素形成堆结构
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last, const Compare& x)
: c(first, last), comp(x) { make_heap(c.begin(), c.end(), comp); }
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last)
: c(first, last) { make_heap(c.begin(), c.end(), comp); }
#else /* __STL_MEMBER_TEMPLATES */
priority_queue(const value_type* first, const value_type* last,
const Compare& x) : c(first, last), comp(x) {
make_heap(c.begin(), c.end(), comp);
}
priority_queue(const value_type* first, const value_type* last)
: c(first, last) { make_heap(c.begin(), c.end(), comp); }
#endif /* __STL_MEMBER_TEMPLATES */
提供的接口
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
//返回堆顶的值,即权值最高的元素
const_reference top() const { return c.front(); }
/* 将元素压入优先级队列
* 先将元素压入vector尾部
* 然后调用push_heap进行调整
*/
void push(const value_type& x) {
__STL_TRY {
c.push_back(x);
push_heap(c.begin(), c.end(), comp);
}
__STL_UNWIND(c.clear());
}
/* 调用pop_heap将权值最大的元素存在vector尾部
* 接着调用vector提供的pop_back弹出尾部元素
*/
void pop() {
__STL_TRY {
pop_heap(c.begin(), c.end(), comp);
c.pop_back();
}
__STL_UNWIND(c.clear());
}
};
例子
#include <iostream>
#include <queue>
using namespace std;
int main()
{
vector<int> vec{0, 1, 2, 3, 4, 5, 6};
priority_queue<int> pri_que(vec.begin(), vec.end());
while(!pri_que.empty())
{
cout << pri_que.top() << endl;
pri_que.pop();
}
pri_que.push(10);
cout << pri_que.top() << endl;
return 0;
}
很简单的一个例子,这里为了方便理解,就只使用了最普通的int
作为权值,你可以尝试声明一个对象,然后定义自己的compare
类作为大小比较标准,然后在创建priority_queue
的时候指定比较标准。
小结
在本小节中,我们分析了priority_queue
的实现,其实它的实现很简单,在我们并没有深入源码的时候可能觉得它很复杂,但是并不是。
priority_queue
主要借用了vector
作为底部容器,以及使用了heap
有关的算法,只是改变了相应的接口,就形成了另外一种数据结构,不得不感叹stl
的精妙。
关于序列式容器,我们就告一段落,接下来我们将进入到关联式容器。但是由于set
和map
这类关联式容器都借助了红黑树实现,所以我们要先对红黑树做个了解。