持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第31天,点击查看活动详情
1、写在前面
大家好,我是翼同学。今天文章的内容是:
- STL中的栈与队列
2、栈
2.1、简介
栈结构中存储的元素满足先进后出(简称LIFO)的规则,如下所示:
在STL中,栈往往是归类为容器适配器(container adapter),在栈的内部结构中,可以使用vector、deque等来实现栈的底层逻辑。也就是说,栈适配器(stack)是一种单端开口的容器,对外提供的接口就有push、pop、top等,并且需要注意,栈的所有数据元素都必须符合先进后出的规则。而且,栈也不支持遍历操作(也就是不提供迭代器)。
栈的一些概念如下:
- 栈顶(
top):允许进行插入或删除操作的一端,称为栈顶; - 栈底(
bottom): 与栈顶相对的另一端称为栈底; - 入栈(
push):在栈顶位置插入数据元素的操作称为入栈(有时也称为进栈、压栈) - 出栈(
pop):删除栈顶元素的操作称为出栈。(也叫弹栈、退栈)
对于stack适配器来说,每次只能访问位于最顶端的元素,只有移除了栈顶元素后,才能访问下面的元素。
2.2、创建栈
(1) 准备
当我们需要创建栈时,需要导入<stack>头文件,并使用std命名空间。
如下所示:
#include <stack>
using namespace std;
这是因为stack适配器:
- 以模板类的形式位于
<stack>头文件中 - 并且定义在
std命名空间里。
(2) 方式一
举个例子:
stack<int> vals;
在上述代码中,我们创建了一个无元素的stack适配器vals,该stack适配器用于存储int类型的元素,并且底层默认使用deque容器。
因此,如果我们没有指定底层实现,那么创建stack适配器时默认是以deque容器为栈的底层结构(因为deque是一个双向队列,只要封住一端,只开通另一端就可以实现栈的逻辑)。
(3) 方式二
举个例子:
stack<int, vector<int>> vals;
上述代码创建了一个使用vector容器作为底层容器的空stack容器适配器vals。需要注意的是,在指定基础容器时,其存储的数据类型必须和stack容器适配器存储的元素类型保持一致。
在<stack>头文件,stack适配器的模板类形式为stack<T, Container=deque<T>>,其中:
T:存储元素的数据类型Container:底层容器的类型,可以是vector、deque、list。
通过模板类的第二个参数Container,我们可以使用除默认容器deque外的其他序列式容器,比如vector和list。
(4) 方式三
举个例子:
list<int> myList {1, 2, 3}; // 定义一个 list 容器
stack<int, list<int>> myStack (myList); // 栈顶元素为 3
在上述代码中,我们使用了一个list容器来初始化一个stack适配器myStack。需要注意,这里使用的容器类型必须和stack所使用的底层容器类型相同,这样才能使用list容器中的数据元素来初始化stack适配器。
(5) 方式四
举个例子:
list<int> vals{100, 200, 300};
stack<int, list<int>> myStack1(vals);
stack<int, list<int>> myStack2 = myStack1;
// 或者也可以这样:stack<int, list<int>> myStack2(myStack1);
在上述代码中,我们使用了一个stack适配器来初始化另一个stack适配器,注意,必须要求二者存储的元素类型以及底层采用的基础容器类型相同。
另外,可以注意到,使用stack适配器给另一个stack适配器进行初始化时,可以有两种方法:
stack<int, list<int>> myStack2 = myStack1;- 等价于
stack<int, list<int>> myStack2(myStack1);
2.3、使用栈
stack容器适配器提供了若干成员函数供我们使用,简单记录如下:
| 成员函数 | 说明 |
|---|---|
empty() | 判断当前是否为空栈(栈中无元素),如果为空栈则返回true,否则返回false |
size() | 获取栈中存储的元素总个数 |
top() | 返回栈顶元素的引用,即类型为T&。注意,如果返回空栈的栈顶元素,则程序将报错 |
push(const T& val) | 调用底层容器的push_back()函数,将参数val的副本压入栈的顶部,称为新的栈顶元素 |
push(T&& obj) | 调用底层容器的有右值引用参数的push_back()函数,将参数压入栈顶 |
pop() | 将栈顶元素弹出 |
swap(stack<T> & other_stack) | 进行互换操作的两个stack容器适配器中的元素(二者存储的元素类型以及底层采用的容器类型必须相同) |
3、队列
前文梳理了一遍栈的特性,事实上,队列的情况也差不多。
3.1、简介
栈结构中存储的元素满足先进先出(简称FIFO)的规则,如下所示:
与stack容器适配器不同,queue容器适配器有2个开放的端口,其中一个用于输入数据,另一个用于输出数据
在STL中,队列也被归类为容器适配器(container adapter),而不是容器。同样的,队列也以deque为缺省情况下采用的底层结构。
在队列中,数据元素按照先进先出的规则进行存储,并且同样不允许有遍历的行为(也就不提供迭代器)。
2.2、创建队列
(1) 准备
当我们需要创建队列时,需要导入<queue>头文件,并使用std命名空间。
如下所示:
#include <queue>
using namespace std;
这是因为queue适配器:
- 以模板类的形式位于
<queue>头文件中 - 并且定义在
std命名空间里。
(2) 方式一
举个例子:
queue<int> vals;
在上述代码中,我们创建了一个无元素的queue适配器vals,该queue适配器用于存储int类型的元素,并且底层默认使用deque容器来实现。
因此,如果我们没有指定底层实现,那么创建queue适配器时默认是以deque容器为栈的底层结构。
(3) 方式二
举个例子:
queue<int, vector<int>> vals;
上述代码创建了一个使用vector容器作为底层容器的空queue容器适配器vals。需要注意的是,在指定基础容器时,其存储的数据类型必须和queue容器适配器存储的元素类型保持一致。
在<queue>头文件,queue适配器的模板类形式为queue<T, Container=deque<T>>,其中:
T:表示存储元素的数据类型Container:表示底层容器的类型,可以是vector、deque、list。
和栈适配器一样,通过模板类的第二个参数Container,我们可以使用除默认容器deque以外的其他序列式容器,比如vector和list。
(4) 方式三
举个例子:
deque<int> vals {100, 200, 300};
queue<int> myQueue(vals);
在上述代码中,我们使用了一个deque基础容器来初始化一个queue容器适配器myQueue。
需要注意,这里使用的容器类型必须和queue所使用的底层容器类型相同,这样才能用deque容器中的数据元素来初始化queue适配器。
(5) 方式四
举个例子:
deque<int> vals{100, 200, 300};
queue<int> myQueue1(vals);
queue<int> myQueue2(myQueue1);
// 或者也可以这样:queue<int> myQueue2 = myQueue1;
在上述代码中,我们使用了一个queue容器适配器myQueue1来初始化另一个queue适配器myQueue2。注意,必须要求二者存储的元素类型以及底层采用的基础容器类型相同。
另外我们可以注意到,一旦使用queue适配器给另一个queue适配器进行初始化时,可以有两种方法:
queue<int> myQueue2(myQueue1);- 等价于
queue<int> myQueue2 = myQueue1;
3.3、使用队列
| 成员函数 | 说明 |
|---|---|
empty() | 判断是否为空队列,如果是则返回true,否则返回false |
size() | 返回queue中元素的个数 |
front() | 返回queue中第一个元素的引用。备注:如果queue是常量,就返回一个常引用;如果queue为空,返回值是未定义的 |
back() | 返回queue中最后一个元素的引用。备注:如果queue是常量,就返回一个常引用;如果queue为空,返回值是未定义的 |
push(const T& obj) | 通过调用底层容器的push_back()函数来将传入参数的副本添加到queue的尾部 |
push(T&& obj) | 通过调用底层容器的具有右值引用参数的push_back()函数来将传入的参数以移动的方式添加到queue的尾部 |
pop() | 删除queue中的首元素 |
swap(queue<T> &other_queue) | 互换两个queue容器适配器中的元素(进行互换操作的两个queue容器适配器存储的元素类型以及底层采用的容器类型必须相同) |
3、写在最后
好了,文章的内容就到这里,感谢观看。