栈和队列

发布时间 2023-10-08 19:57:21作者: 啊鸧仓_Eliauk

栈(\(\text {stack}\))是一种后进先出(\(\text {Last In First Out,LIFO}\))的线性表,顾名思义,后入栈的元素反而先出栈,其限制是只能在一端插入与删除,

就像下面这样,只有一端有开口,另一端则是封死的。

\[\large\text {栈顶} \begin{array}{c|c|c|c|c|c|c|c|{3}{r@{.}l|}} \hline \ 0&1&2&3&4&5&6&7&...\\ \hline \end{array} 栈底 \]

一般的,我们将栈能插入与删除的一端称为「栈顶」,而不能进行操作的一端称为「栈底」。

同时,插入操作一般称作入栈或压栈(\(\text {push}\)),删除操作称作出栈或弹出(\(\text {pop}\))。

一个通俗的例子是把栈看作一个盘子堆,只能在盘子堆的顶上拿取盘子,如果从中间抽出/插入盘子,盘子堆就会倒塌,碎成碎片。

手写栈

接下来我们尝试一下,使用静态数组来模拟一个栈。

从增加元素开始,先考虑栈底与栈顶的位置,很明显,为了不限制栈的大小与方便,栈底设在 \(1\) 的位置比较好,

再用一个 int \(top\) 指向当前栈顶的位置

int top = 0,s[MAXN] = {0}; // 一开始栈内没有元素,所以 top 指向 0 表示当前栈内为空

当进行压栈时,新的元素会被「放」在原来的栈顶上,

此时的栈顶就是 \(top + 1\),再赋值即可。

void push(int x){ // 传参需要压栈的元素 x
    s[top ++] = x; // 压入元素
}

因为只是操作了一次数组 \(s\) 与 变量 \(top\),所以时间复杂度为 \(O(1)\)

接下来是删除元素,可以想到将栈顶移动到原栈顶的下一个元素上,以删除原本的元素。

但是要判断一下当前 \(top\) 是否指向的是 \(0\)(空栈),否则就会收获 \(\color {Purple} {\texttt {RE}} \times \infty\)

int pop(){
    if(top)top --;
    else return -1;
    return 0;
}

同样的,时间复杂度为 \(O(1)\)

而还有一个常用操作就是取栈当前的元素个数,因为 \(top\) 指向了栈顶,所以 \(top\) 就是栈当前的元素个数。

int size(){
    return top;
}

\(\text {STL stack}\)

除了可以手写栈,强大的 \(\text {STL}\) 还为我们提供了 stack 关键字,用法如下:

stack<Type> s 声明一个 Type 类型的栈 \(s\)

s.top() 返回一个 int,表示当前栈顶的值。\(O(1)\)

s.push(x) 将元素 \(x\) 压入栈 \(s\)\(O(1)\)

s.pop() 弹出栈 \(s\) 的栈顶元素。\(O(1)\)

s.empty() 返回一个 booltrue 表示栈 \(s\) 为空,false 反之。\(O(1)\)

s.size() 返回一个 int,表示栈 \(s\) 的元素个数。\(O(1)\)

更多方法见微软文档 \(\texttt{stack STL}\) 部分。

队列

队列(\(\text {queue}\))与栈相反,是一种先进先出(\(\text {First In First Out,FIOF}\))的线性表,也就是说,先入队的元素先出队,与生活中的「排队」是一样的。

而队列的限制则是只能在一端插入,在另一端删除,如下图:

\[\large 队头 \gets 0\ \ \begin{array}{c|c|c|c|c|c|c|c|c|{3}{r@{.}l}} \hline \ \ \ &1&2&3&4&5&6&7&8&\ \ \\ \hline \end{array}\gets 9 \ \ 队尾 \]

一般的,我们将队列能进行插入的一端称作「队尾」,进行删除的一端称作「队头」。

而插入操作一般称作入队(\(\text {push}\)),删除一般称作出队(\(\text {pop}\))。

\(\text {STL queue}\)

强大的 \(\text {STL}\) 自然也为我们提供了 queue 关键字。

除了可以手写栈,强大的 \(\text {STL}\) 还为我们提供了 stack 关键字,用法如下:

queue<Type> q 声明一个 Type 类型的队列 \(q\)

q.front() 返回一个 int,表示当前队头的值。\(O(1)\)

q.push(x) 将元素 \(x\) 入队队列 \(q\)\(O(1)\)

q.pop() 队列 \(q\) 的队头元素出队。\(O(1)\)

q.empty() 返回一个 booltrue 表示队列 \(q\) 为空,false 反之。\(O(1)\)

q.size() 返回一个 int,表示队列 \(q\) 的元素个数。\(O(1)\)

更多方法见微软文档 \(\texttt{queue STL}\) 部分。