【C++闯关笔记】STL:stack与queue的学习和使用
系列文章目录
上一篇文章:【C++闯关笔记】STL:list 的学习和使用-CSDN博客
文章目录
目录
前言
一、概念
二、使用介绍
1.stack:后进先出
核心特性
核心操作
细节与陷阱
使用场景
2.queue:先进先出
核心特性
核心操作
细节与陷阱
使用场景
三、模拟实现
1.stack模拟实现
2.queue模拟实现
总结
前言
C++中的stack、queue与数据结构中的栈、队列本质上是一样的,不同之处仅在C++将其它们封装成了类并添加了一些新东西,其他方面与数据的栈、队列完全一致。
一、概念
核心概念:它们都是“容器适配器”
首先,要建立一个重要的认知:stack 和 queue 都不是独立的容器,而是“容器适配器”。
你可以把它们想象成对某种底层容器(如 list 、vector等 )的接口包装和功能限制。它们基于vector、list 或者其他什么底层容器构建,但只暴露了符合特定数据结构(栈或队列)规则的接口。
二、使用介绍
1.stack:后进先出
核心特性
①LIFO: Last-In, First-Out,后进先出。就像一摞盘子,取的总是最上面的那个(也就是最后放上去的)。
②栈顶:我们约定进行操作的那一端称为栈顶,另一端则为栈底。
核心操作
-
push(const T& value)
: 压栈,将元素放入栈顶。 -
pop()
: 弹栈,移除栈顶元素(并不返回元素!)。 -
top()
: 访问栈顶元素(返回引用)。 -
empty()
: 判断栈是否为空。 -
size()
: 返回栈中元素个数。
细节与陷阱
①pop( ) 返回 void,不能用来获取值。正确的做法是先通过top( )获取栈顶数据,在pop( )移除栈顶数据;
②警惕空栈。对空栈调用top 和pop 操作是未定义行为,绝大多数情况下会导致程序崩溃;
使用场景
-
函数调用栈:计算机系统最核心的应用,记录函数调用关系和局部变量。
-
表达式求值:处理括号匹配、将中缀表达式转换为后缀表达式。
-
撤销操作:编辑器中的撤销,将操作压栈,撤销时弹出。
-
深度优先搜索:DFS算法通常使用栈来实现。
2.queue:先进先出
核心特性
①FIFO: First-In, First-Out,先进先出。就像现实生活中的排队,先来的人先接受服务。
②出数据的一端称为队头,入数据的一端称为队尾。
核心操作
-
push(const T& value)
: 入队,将元素放入队尾。 -
pop()
: 出队,移除队首元素(同样不返回元素!)。 -
front()
: 访问队首元素。 -
back()
: 访问队尾元素。 -
empty()
: 判断队列是否为空。 -
size()
: 返回队列中元素个数。
细节与陷阱
①f
ront()
/back()
和pop()
也必须分两步走。先通过 front / back 获取数据后,再 pop 出数据。②警惕空队列。对空队列调用 f
ront()
/back()
和pop()
同样是未定义行为。
使用场景
-
广度优先搜索:BFS算法的核心数据结构。
-
消息队列:在网络通信或多线程中,用于在不同线程或进程间传递数据。
-
缓冲区:例如打印机任务队列,先提交的打印任务先执行。
-
模拟现实排队:银行叫号系统等。
三、模拟实现
1.stack模拟实现
考虑到 stack 只在栈顶频繁进行数据的写入写出,那么选择一个插入/删除数据操作效率高的底层容器,进行封装无疑是最好的选择。
vector 的push_back与push_pop 时间复杂度均为O(1),故这里我们采用封住 vector 来模拟实现stack。
模拟代码如下:
#include <vector>namespace karsen
{template<typename T>class stack{public:stack(){}void push(const T& x){_st.push_back(x);}T& top(){return _st.back();}bool empty(){return _st.empty();}size_t size(){return _st.size();}void pop(){_st.pop_back();}private:std::vector<T> _st;};
}
2.queue模拟实现
相较于 stack 的单侧数据增删,queue需要在队头/队尾频繁进行数据增删,vector 显然不再适合,此时本质为双向循环链表的 list 就比较合适。
模拟代码如下:
#pragma once
#include<list>namespace karsen
{template<typename T>class queue{public:queue(){}bool empty(){return _qu.empty();}void push(const T& x){_qu.push_back(x);}void pop(){_qu.pop_front();}T& back(){return _qu.back();}T& front(){return _qu.front();}size_t size(){return _qu.size();}private:std::list<T> _qu;};};
总结
本文介绍了stack与queue的概念以及使用,最后给出了 vector 模拟实现的stack代码;用 list 模拟实现的 queue代码。
值得一提的是STL源码中,stack与queue都是基于deque进行封装的,deque不仅提供O(1)的头尾操作,并且没有vector扩容时带来的时间损耗。
最后,如果希望进一步探究栈与队列的使用,可参考:
【数据结构】栈_栈 数据结构-CSDN博客
【数据结构】队列_数据结构队列-CSDN博客
读完点赞,手留余香~