一、栈的概念
栈是一种只允许 在 一端 进行数据插入和删除操作的 线性表。
生活中的案例 :
如果定义了一个栈结构,那么
添加和删除元素只能在栈顶进行
。不能随意位置添加和删除元素,这是栈这个数据结构的特性,也是规定。
二、栈的模拟实现
2.1 创建
1 ) 本质上还是线性表 , 因此可以创建一个足够大的数组 , 充当栈结构 。
2 )定义一个变量 n , 用来记录栈中元素的个数 , 同时可以标记栈顶的位置
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e5 + 10;
//栈
int stk[N];
int n;
int main()
{
return 0;
}
2.2 进栈
1) 这里依旧舍弃下标为 0 的位置,有效元素从 1 开始记录。2 )进栈操作,那就把元素放在栈顶位置即可时间复杂度:O(1)本质上是顺序表里面的尾插3 )这里有一个小BUG ,栈满了就不可以再继续进栈了这里我们在调用函数的时候知道就好了 , 如果在工程中 , 就一定需要外加判断;这里是为了让我们了解栈的特性 。
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e5 + 10;
//栈
int stk[N];
int n;
//入栈
void push(int x)
{
stk[++n] = x;
}
//遍历栈
void print()
{
for(int i = 1 ; i<= n ; i++)
{
cout << stk[i] << " ";
}
cout << endl;
}
int main()
{
push(1);
push(2);
push(3);
push(4);
//1 2 3 4
print();
return 0;
}
2.3 出栈
1 )不需要真的删除元素,只需要将元素个数减 1 ,就相当于删除栈顶元素2 )时间复杂度:O(1)3 ) 类比顺序表的尾删4 )这里有一个小BUG ,空栈不可删
//出栈
void pop()
{
n--;
}
2.4 栈顶元素
查询栈顶元素。因为栈特殊的规定,不支持遍历整个栈中的元素。因此,需要查找栈中元素的时候,只 能查找到栈顶元素。时间复杂度:O(1)
//栈顶元素
int top()
{
return stk[n];
}
2.5 判空
//判断栈是否为空
bool empty()
{
return n == 0;
}
2.6 有效元素的个数
//有效元素的个数
int size()
{
return n;
}
2.7 所有测试代码
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e5 + 10;
//栈
int stk[N];
int n;
//入栈
void push(int x)
{
stk[++n] = x;
}
//遍历栈
void print()
{
for(int i = 1 ; i<= n ; i++)
{
cout << stk[i] << " ";
}
cout << endl;
}
//出栈
void pop()
{
n--;
}
//栈顶元素
int top()
{
return stk[n];
}
//判断栈是否为空
bool empty()
{
return n == 0;
}
//有效元素的个数
int size()
{
return n;
}
int main()
{
push(1);
push(2);
push(3);
push(4);
//1 2 3 4
print();
while(!empty())
{
pop();
print();
}
return 0;
}
三、stack
3.1 创建
stack<T> st;
T : 可以是任意数据类型
3.2 size/empty
1) size : 返回栈里实际元素个数
2)empty : 返回栈是否为空。
时间复杂度: O(1) 。
3.3 push/pop
1)push :进栈
2)pop :出栈
时间复杂度: O(1) 。
3.4 top
top :返回栈顶元素,但是不会删除栈顶元素。时间复杂度: O(1)
3.5 所有测试代码
#include <iostream>
#include <cstdio>
#include <stack>
using namespace std;
stack<int> st;
int main()
{
//1~10 进栈
for(int i = 1;i<=10;i++)
{
st.push(i);
}
while(st.size() )
{
cout << st.top() << " ";
st.pop() ;
}
return 0;
}
四 、 算法题
4.1 【模板】栈
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e6 + 10;
typedef unsigned long long LL;
int top;
LL stk[N];
int main()
{
int T;
cin >> T;
while(T--)
{
//清空栈
top = 0;
int n ;
cin >> n;
while(n--)
{
string op;
cin >> op;
if(op == "push")//入栈
{
LL x;
cin >> x;
stk[++top] = x;
}
else if(op == "pop")
{
if(top == 0)
cout << "Empty" << endl;
else
top--;
}
else if(op == "query")
{
if(top == 0) cout << "Anguei!" << endl;
else
cout << stk[top] << endl;
}
else
{
cout << top << endl;
}
}
}
return 0;
}
4.2 有效的括号
class Solution {
public:
bool isValid(string s) {
stack<char> st;
for(auto ch: s)
{
if(ch == '(' || ch == '[' || ch == '{')
{
st.push(ch);
}
else
{
if(st.empty()) return false;
char left = st.top();
if(ch == ')' && left != '(') return false;
if(ch == ']' && left != '[') return false;
if(ch == '}' && left != '{') return false;
st.pop();
}
}
return st.empty();
}
};
4.3 验证栈序列
#include <iostream>
#include <cstdio>
#include <stack>
using namespace std;
const int N = 1e5 + 10;
int q,n;
int st1[N],st2[N];
int main()
{
cin >> q;
while(q--)
{
cin >> n;
for(int i = 1;i <= n ; i++) cin >> st1[i];
for(int i = 1; i <= n ; i++) cin >> st2[i];
stack<int> st;
int j = 1 ;//标记poped的第一个元素的下标
for(int i = 1;i<= n ; i++)
{
//进栈
st.push(st1[i]);
//判断是否入栈
while(j <= n && st.size() && st2[j] == st.top())
{
st.pop();
j++;
}
}
if(st.empty()) cout << "Yes" << endl;
else cout << "No" << endl;
}
return 0;
}
4.4 后缀表达式
#include <iostream>
#include <cstdio>
#include <stack>
using namespace std;
int main()
{
stack<int> st;
char ch;
int num = 0;
while(cin >> ch)
{
if(ch == '@') break;
else if(ch == '.')
{
st.push(num);
num = 0;
}
else if(ch >= '0' && ch <= '9')
{
num = num * 10 + ch -'0';
}
else
{
//操作符
int b = st.top();st.pop();
int a = st.top();st.pop();
if(ch == '+') st.push(a+b);
else if(ch == '-') st.push(a-b);
else if(ch == '*') st.push(a*b);
else st.push(a/b);
}
}
cout << st.top() << endl;
return 0;
}
4.5 括号序列
#include <iostream>
#include <cstdio>
#include <stack>
using namespace std;
const int N = 110;
string s;
bool st[N] ; //标记是否成功匹配
string ret; //返回的字符串
stack<int> stk; //存储左括号的下标值
int main()
{
cin >> s;
int n = s.size() ;
for(int i = 0;i < n;i++)
{
if(s[i] == '(' || s[i] == '[') stk.push(i);
else
{
//右操作符
if(stk.empty()) continue;
char ch = s[stk.top()];
if((ch == '(' && s[i] == ')' )|| (ch == '[' && s[i] == ']'))
{
st[stk.top()] = true;
st[i] = true;
stk.pop();
}
}
}
for(int i = 0;i < n ; i++)
{
char ch = s[i];
if(st[i]) ret += ch;
else
{
//不能匹配就需要添上相应的括号
if(ch == '(')
{
ret += ch;
ret += ')';
}
else if(ch == ')')
{
ret += '(';
ret += ch;
}
else if(ch == '[')
{
ret += ch;
ret += ']';
}
else if(ch == ']')
{
ret += '[';
ret += ch;
}
}
}
cout << ret << endl;
return 0;
}