【C++ STL 库】解析stack、queue、priority_queue类
目录
引言
一、stack 类解析
1. 基本概念
2. 常用接口
3. 自我实现代码解析
二、queue 类解析
1. 基本概念
2. 常用接口
3. 自我实现代码解析
三、priority_queue 类解析
1. 基本概念
2. 常用接口
3. 自我实现代码解析
四、总结
引言
在 C++ 编程中,stack
、queue
和priority_queue
作为 STL 提供的三种容器适配器,以简洁优雅的方式满足了不同场景下的数据处理需求。当你需要实现如函数调用栈、表达式求值等后进先出(LIFO)逻辑时,stack
会是你的得力助手;若遇到模拟排队系统、消息传递队列等先进先出(FIFO)场景,queue
能让你的代码清晰高效;而在任务调度、路径规划等需要根据优先级处理元素的场景中,priority_queue
通过堆结构自动维护元素优先级,让复杂的排序逻辑变得简单透明。这三种适配器就像三把精密的工具,各自解决特定类型的问题,帮助开发者更专注于业务逻辑而非数据结构的底层实现。接下来,让我们深入了解它们的内部机制与实现细节。
一、stack 类解析
1. 基本概念
stack 是一种后进先出(LIFO)的数据结构,它只允许在栈顶进行插入和删除操作。在 C++ STL 中,stack 是一种适配器容器,默认基于 deque 实现。
2. 常用接口
push()
: 向栈顶添加元素pop()
: 删除栈顶元素top()
: 返回栈顶元素的引用empty()
: 判断栈是否为空size()
: 返回栈中元素的个数
3. 自我实现代码解析
以下是 stack 类的简化自我实现:
pragma once
#include <deque>namespace lmr
{using namespace std;template < class T, class Container = deque <T> >class stack{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_back();}const T& top() const{return _con.back();}size_t size() const{return _con.size();}bool empty() const{return _con.empty();}private:Container _con;};
}
代码解析:
- 模板参数: 第一个模板参数 T 是元素类型,第二个模板参数 Container 是底层容器类型,默认使用 deque。
- 底层容器: 使用成员变量 _con 存储数据,通过调用底层容器的接口实现 stack 的功能。
- 接口实现: 所有操作都是基于底层容器的尾部操作,确保符合栈的 LIFO (先进后出)特性。
二、queue 类解析
1. 基本概念
queue 是一种先进先出(FIFO)的数据结构,它允许在队尾插入元素,在队头删除元素。在 C++ STL 中,queue 也是一种适配器容器,默认基于 deque 实现。
2. 常用接口
push()
: 向队尾添加元素pop()
: 删除队头元素front()
: 返回队头元素的引用back()
: 返回队尾元素的引用empty()
: 判断队列是否为空size()
: 返回队列中元素的个数
3. 自我实现代码解析
以下是 queue 类的简化自我实现:
#pragma once
#include <vector>
#include <list>
#include <iostream>
#include <deque>namespace lmr
{using namespace std;template < class T, class Container = deque <T> >class queue{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_front();}const T& back() const{return _con.back();}const T& front() const{return _con.front();}size_t size() const{return _con.size();}bool empty() const{return _con.empty();}private:Container _con;};
}
代码解析:
- 模板参数: 与 stack 类似,支持自定义底层容器,默认使用 deque。
- 底层容器: 使用 deque 的
push_back()
和pop_front()
方法实现 FIFO(先进先出)特性。 - 接口实现: 通过 front () 访问队头元素,通过 back () 访问队尾元素,入队用 push_back (),出队用 pop_front ()。
三、priority_queue 类解析
1. 基本概念
priority_queue 是一种优先级队列,它保证队头元素始终是优先级最高的元素。默认情况下,使用元素类型的<
运算符确定优先级,较大的元素优先级更高。在 C++ STL 中,priority_queue 基于堆(heap)实现,默认使用 vector 作为底层容器。
2. 常用接口
push()
: 插入元素到适当位置pop()
: 删除优先级最高的元素top()
: 返回优先级最高的元素empty()
: 判断队列是否为空size()
: 返回队列中元素的个数
3. 自我实现代码解析
以下是 priority_queue 类的简化自我实现:
#pragma once#include <vector>template <class T>
class Less
{
public:bool operator()(const T& x, const T& y){return x < y;}
};template <class T>
class Greater
{
public:bool operator()(const T& x, const T& y){return x > y;}
};namespace lmr
{//默认是大堆template <class T, class Container = vector<T>, class Compare = Less<T>>class priority_queue{public://向上调整算法void AdjustUp(int child){Compare com;int parent = (child - 1) / 2;while(child > 0){if(com(_con[parent], _con[child])){swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}void push(const T& x){_con.push_back(x);AdjustUp(_con.size() - 1);}//向下调整算法void AdjustDown(int parent){//先假设左孩子小int child = parent*2 + 1;Compare com;while(child < _con.size()){//比较孩子if(child + 1 < _con.size() && com(_con[child], _con[child + 1])){child++;}//调整if(com(_con[parent], _con[child])){swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();AdjustDown(0);}const T& top(){return _con[0];}size_t size(){return _con.size();}bool empty(){return _con.empty();}private:Container _con;};
}
代码解析:
- 模板参数: 除了元素类型和底层容器外,还支持自定义比较器,默认使用 std::less。这里代码实现了两个自定义比较类Less Greater 重载了operator(),使其对象可以像函数一样使用。所以这类比较类在c++中称为仿函数。
- 底层容器: 使用 vector 存储数据,利用标准库的堆算法维护堆结构。
- 接口实现:
push()
: 先将元素添加到容器尾部,再调用push_heap
调整堆结构。pop()
: 先调用pop_heap
将堆顶元素移到容器尾部,再删除尾部元素。top()
: 直接返回容器的第一个元素,即堆顶元素。
四、总结
通过自我实现可以看出,STL 中的 stack、queue 和 priority_queue 都是基于其他容器的适配器。它们通过封装底层容器的接口,提供了特定的数据结构功能,既保证了功能的正确性,又提供了灵活性(可自定义底层容器)。理解这些适配器的实现原理,有助于我们更好地使用它们,并且在需要时能够自己实现类似的数据结构。