一、stack是什么?
1.栈的定义和存储
栈(Stack)是一种只允许在一端进行插入或删除操作的线性表。栈顶(Top)是允许插入和删除的那一端,而栈底(Bottom)是固定的另一端。栈可以采用顺序存储结构,也称为顺序栈,或者采用链式存储结构,也称为链栈。
2.适配器容器的定义
适配器容器是指基于其他容器实现的容器,也就是说适配器容器包含另一个容器作为其底层容器,在底层容器的基础上实现适配器的功能。stack默认的底层容器是deque(队列),底层容器也可以指定为vector或list。
3.stack(栈容器)
C++ 中的 std::stack 是一种容器适配器,提供了一种后进先出(LIFO, Last In First Out)的数据结构,不支持随机访问。
主要特性:
后进先出(LIFO):最后插入的元素最先被访问或移除。
栈顶操作:只能在栈顶插入、访问和移除元素。
受限接口:std::stack 只提供插入、删除、访问栈顶、检查大小和判断是否为空等基本操作,不支持像 std::vector 这样的随机访问。
二、使用步骤
1.引入库
代码如下(示例):
import<stack>
2.栈的初始化
代码如下(示例):
stack<int>s1; //默认底层容器为deque
stack<int,vector<int>>s2 //指定底层容器为vector
stack<int,list<int>>s3 //指定底层容器为list
3.栈的主要成员函数
接口 | 作用 |
---|---|
empty() | 判断栈是否为空。如果栈为空,返回 true,否则返回 false。 |
size() | 返回栈中实际的元素个数。 |
push(e) | 将元素e压入栈顶。 |
top() | 访问栈顶元素。 |
pop() | 移除栈顶元素。 |
注意:在调用top()和pop()之前务必通过empty()检测,确保栈是非空的,否则会出现错 误。
三、栈的C++代码
#include <iostream>
#include <stdexcept>
using namespace std;
#define MAXSIZE 100 // 定义栈的最大容量
template<class T>
class Stack {
private:
T* arr; // 使用动态分配的数组来存储栈元素
int top;
int capacity;
public:
Stack() : top(-1), capacity(MAXSIZE) {
// 构造函数中动态分配具有初始容量的数组
arr = new T[capacity];
}
~Stack() {
// 析构函数中释放动态分配的数组内存
delete[] arr;
}
//入栈
void push(T element) {
if (top < capacity - 1) {
arr[++top] = element;
} else {
// 当栈满时,尝试动态扩展栈的容量
int newCapacity = capacity * 2;
T* newArr = new T[newCapacity];
for (int i = 0; i <= top; ++i) {
newArr[i] = arr[i];
}
delete[] arr;
arr = newArr;
capacity = newCapacity;
arr[++top] = element;
}
}
//出栈
T pop() {
if (top >= 0) {
return arr[top--];
} else {
throw underflow_error("Stack Underflow");
}
}
// 查看栈顶元素
T top() {
if (top >= 0) {
return arr[top];
} else {
throw underflow_error("Stack Underflow");
}
}
//判断非空
bool Empty() {
return top == -1;
}
//栈中实际元素数量
int size() {
return top + 1;
}
};
四、STL中 stack(栈容器)的应用
问题:对于一个栈,元素依次入栈和出栈,给定一个出栈顺序序列,判断这个序列是否合理。
#include <iostream>
#include <stack>
#include <vector>
using namespace std;
// 这个函数用于判断输入的整数序列是否为一个合理的入栈和出栈顺序。
// 例如,对于一个栈,元素依次入栈和出栈,给定一个出栈顺序序列,判断这个序列是否合理。
bool isGoodSeq(const vector<int>& seq) {
stack<int> stk;
int exp = 1;
// 遍历输入的序列。
for (int num : seq) {
// 如果栈为空或者栈顶元素小于当前要匹配的元素,
// 则将预期的连续整数依次入栈,直到栈顶元素等于当前要匹配的元素或者栈已满。
while (stk.empty() || stk.top() < num) {
stk.push(exp++);
}
// 如果栈顶元素等于当前要匹配的元素,说明找到了正确的出栈顺序,将栈顶元素弹出。
if (stk.top() == num) {
stk.pop();
} else {
// 如果栈顶元素不等于当前要匹配的元素,说明这个序列不是合理的顺序,返回 false。
return false;
}
}
// 如果遍历完整个序列都没有出现不合理的情况,说明这个序列是合理的顺序,返回 true。
return true;
}
int main() {
vector<int> seq1 = {4, 3, 5, 1, 2};
vector<int> seq2 = {1, 2, 3, 4, 5};
cout << "Seq1 is good: " << (isGoodSeq(seq1)? "Yes" : "No") << endl;
cout << "Seq2 is good: " << (isGoodSeq(seq2)? "Yes" : "No") << endl;
return 0;
}
结果如下:
这段代码利用一个辅助栈来模拟元素的入栈和出栈过程,通过遍历输入的整数序列,判断其是否可以由一个栈的入栈和出栈操作得到。如果在遍历过程中发现某个元素既不能从栈顶弹出,也不能通过入栈操作得到,那么就说明这个序列不是合理的入栈和出栈顺序。