1. queue介绍及使用方法
queue
是 C++ 标准模板库(STL)中的容器适配器,遵循先进先出(FIFO)原则。它基于其他容器(如deque
或list
)实现,仅允许在队尾插入元素,在队头删除元素。stack的底层是一个
deque<T>
(双端队列),虽然deque是可以从两端来进行操作的,但是我们只要只提供一端的接口,那么就可以来把它当做stack来使用。因为
queue
需要支持高效的 “队尾插入”(push
)和 “队头删除”(pop
)操作,而deque
的push_back
(尾插)和pop_front
(头删)操作均能在常数时间内完成,且无需像vector
那样在头删时移动大量元素,也无需像list
那样维护额外的指针开销,综合性能更优。
2. queue的常用函数
函数名 | 函数作用 |
---|---|
void push(const T& x) | 在尾巴部插入元素 |
void pop() | 抛出一个头部元素 |
T& front() | 返回头部元素 |
T& back() | 返回尾部元素 |
size_t size() | 返回队列的大小 |
bool empty() | 判断是否为空,为空就返回true |
3. template
在这里写两个calss是为了方便使用,这两个模板参数实际上是各司其职,只是语法上要求写在同一个 template<>
里,使用时会根据场景自动匹配对应的参数。
- 前面的
T
是明确指定栈中元素的类型(比如int
、string
等),这是栈对外提供的 “数据类型契约”—— 栈里只能存T
类型的东西。- 后面的
Container
是指定用什么容器来存储这些T
类型的元素,而默认的deque<T>
就是 “用双端队列来存T
类型元素” 的意思。
PS:只写后面那一个理论上来说也是可以的,但是会让用户使用门槛变高,比如想声明一个存 int
的栈,用户不能直接写 stack<int>
,而必须写成 stack<deque<int>>
(如果想用默认容器),或者 stack<vector<int>>
。这会让接口变得不直观 —— 用户需要先知道底层容器的类型,才能正确声明栈,违背了 “栈是容器适配器,用户无需关心底层实现” 的设计初衷。
PS:只写前面哪一个是不行的,如果只写 template<class T>
,就意味着用户无法指定底层容器了 —— 因为没有 Container
这个参数来接收用户自定义的容器类型。
template<class T, class Container = deque<T>>
4. private
这就是申明一个私有成员_con。
private:
Container _con;
5.pop()
抛出队头,因为队列是先进先出的。
void pop()
{
_con.pop_front();
}
6. front()
返回队头元素。
PS:这边使用T&是为了调用者可以直接修改队列中真正的队头元素,避免不必要的拷贝开销。
T& front()
{
return _con.front();
}
7. back()
返回队尾元素。
队列是先进先出,但是在很多场景下,除了需要知道 “最早入队的元素”(队头,front()
),还可能需要获取 “最新入队的元素”(队尾)。
back()只是“读取” 队尾元素,不会修改队列的结构或元素顺序,因此不会破坏其核心逻辑。
T& back()
{
return _con.back();
}
8. size()
通过调用双端队列的size()来返回队列size的大小。
size_t size()
{
return _con.size();
}
9. empty()
判断是否为空,为空就返回true。
bool empty()
{
return _con.empty();
}
10. push()
在队列尾部插入一个元素。
void push(const T& x)
{
_con.push_back(x);
}
11. 总结
综上,queue
凭借简洁的接口、高效的底层实现,成为处理顺序依赖场景的理想选择。理解其基于deque
的适配逻辑,能帮助开发者更合理地运用队列解决实际问题。
以下是queue的完整代码:
template<class T, class Container = deque<T>>
class queue
{
public:
void push(const T& x)
{
_con.push_back(x);
}
void pop()
{
_con.pop_front();
//_con.erase(_con.begin());
}
T& front()
{
return _con.front();
}
T& back()
{
return _con.back();
}
size_t size()
{
return _con.size();
}
bool empty()
{
return _con.empty();
}
private:
Container _con;
};