我们在前面说stack的时候已经说过了什么叫容器适配器,如果有不了解的,可以去前面 看一看。
这里呢,我们主要讲下queue,作为生活里面我们司空见惯了的现像,应该是不叫好理解的。
1、queue容器的定义
和 stack 栈容器适配器不同,queue 是一种先进先出(FIFO)的数据结构,queue 容器适配器有 2 个开口,其中一个开口专门用来输入数据,另一个专门用来输出数据。但是queue元素的加入和取出是固定的,比如加入只能在队尾加入,取出只能在队前,其他地方都不能进行元素的操作。简单的说,queue不能进行遍历。
我们先开一下queue的示意图:
由上面的示意图我们可以看出,queue的访问只能访问到队前和队尾的两个元素,不能逾越它的规则,访问对中间的元素。
下面我们看下SGI源码中对queue的定义:
template <class _Tp, class _Sequence>
class queue {
// requirements:
__STL_CLASS_REQUIRES(_Tp, _Assignable);
__STL_CLASS_REQUIRES(_Sequence, _FrontInsertionSequence);
__STL_CLASS_REQUIRES(_Sequence, _BackInsertionSequence);
typedef typename _Sequence::value_type _Sequence_value_type;
__STL_CLASS_REQUIRES_SAME_TYPE(_Tp, _Sequence_value_type);
#ifdef __STL_MEMBER_TEMPLATES
template <class _Tp1, class _Seq1>
friend bool operator== (const queue<_Tp1, _Seq1>&,
const queue<_Tp1, _Seq1>&);
template <class _Tp1, class _Seq1>
friend bool operator< (const queue<_Tp1, _Seq1>&,
const queue<_Tp1, _Seq1>&);
#else /* __STL_MEMBER_TEMPLATES */
friend bool __STD_QUALIFIER
operator== __STL_NULL_TMPL_ARGS (const queue&, const queue&);
friend bool __STD_QUALIFIER
operator< __STL_NULL_TMPL_ARGS (const queue&, const queue&);
#endif /* __STL_MEMBER_TEMPLATES */
public:
typedef typename _Sequence::value_type value_type;
typedef typename _Sequence::size_type size_type;
typedef _Sequence container_type;
typedef typename _Sequence::reference reference;
typedef typename _Sequence::const_reference const_reference;
protected:
_Sequence c;
public:
queue() : c() {}
explicit queue(const _Sequence& __c) : c(__c) {}
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
reference front() { return c.front(); }
const_reference front() const { return c.front(); }
reference back() { return c.back(); }
const_reference back() const { return c.back(); }
void push(const value_type& __x) { c.push_back(__x); }
void pop() { c.pop_front(); }
};
其实,我们也能够很明显的发现,我们对queue的操作,都是直接调用了它的底层序列容器的方法,这一点上和stack是一致的。
2、queue容器的创建
#include <queue>
using namespace std;
1、创建一个不包含任何元素的 queue 适配器,并采用默认的 deque 基础容器
std::queue<int> data;
2、创建指定底层容器的 stack 适配器
std::queue<int, std::list<int>> data; //以list为底层容器,创建一个空的queue
std::list<int> values {5, 6, 7, 8};
std::queue<int, std::list<int>> data(values);
我们通过上一节的学习也能够看出来,其实queue的底层容器是没有stack那么多的,只有list是支持的。
3、基础容器来初始化
//跟默认的基本上是一样的,这边需要注意的是,deque的元素类型必须和queue的保持一致
std::deque<int> data {1, 2, 3};
std::queue<int> data1(data);
4、赋值
std::deque<int> data{1, 2, 3};
std::queue<int> data1(data);
std::queue<int> data2 = data1;
通过这种赋值的方法来创建新的queue适配器,是不会影响第一个适配器的,也就是是不会影响data1的。
3、迭代器
前面我们已经说过了,queue只能访问队前和队尾的两个元素,那也就意味着queue是不能被遍历的,也就是说,queue是没有迭代器的。
4、成员函数
成员函数 | 函数说明 |
---|---|
empty() | 判断queue是否为空,为空返回true,否则返回false |
size() | 返回queue中的元素的实际个数 |
(const) front() | 返回queue队列第一个元素的引用(const),栈为空则返回未定义元素 |
(const) back() | 返回queue队列最后一个元素的引用(const),栈为空则返回未定义元素 |
push(const T& val) | 调用底层的push_back函数,先复制,再插入副本 |
push(T&& obj) | 移动元素的方式在queue队尾添加元素,底层容器支持 |
pop() | 移除queue第一个元素 |
emplace(arg…) | 在队尾插入元素 |
swap(queue & other_queue) | 将两个 queue适配器中的元素进行互换,两个队列的基础容器、元素类型必须相同 |
5、使用
queue的使用,我们参考了下stack的运用,比较简单。
#include <iostream>
#include <queue>
#include <list>
using namespace std;
template<class T>
void display(T& data) //注意函数的入参,会修改传入的变量
{
// int nCount = data.size();
// for(int nIndex = 0; nIndex < nCount; ++nIndex) //如果使用for循环遍历,则不能用data.size()直接代替nCount,因为data.front()会改变data.size()
while (!data.empty())
{
cout << data.front() << " ";
data.pop();
}
cout << endl;
}
int main(int argc, char* argv[])
{
queue<int> data0;
for(int nIndex = 0; nIndex < 10; ++nIndex)
{
data0.push(nIndex);
}
display(data0); // 0 1 2 3 4 5 6 7 8 9
queue<int, list<int>> data;
for(int nIndex = 1; nIndex <= 10; ++nIndex)
{
data.push(nIndex * 2);
}
display(data); // 2 4 6 8 10 12 14 16 18 20
list<int> values {5, 6, 7, 8};
queue<int, list<int>> data1(values);
display(data1); // 8 7 6 5
list<int> value {11, 12, 13, 14};
queue<int, list<int>> data2(value);
queue<int, list<int>> data3 = data2;
display(data3); // 11 12 13 14
display(data2); // 11 12 13 14
return 0;
}
结果如下:
其实,容器有很多,重要的是我们需要能够在面对实际场景时,能够准确的选择容器。