算法学习专栏——栈(一)
前言
先照顾一下基础薄弱的同学,介绍一下什么是栈。
栈就是一个头开底闭的一个盒子,首先看一下下面的动画视频来了解一下栈
进栈操作(栈顶插入一个元素):这个过程是一个一个进的,球1进完,球2再进
出栈操作(从栈顶弹出一个数):必须按照从上往下的顺序弹出栈里元素操作,比如下图,不可以先将球1拿出来,必须先将球2拿出来之后再拿球1
空栈:栈内没有小球(元素)
一、模拟栈(简单-)
实现一个栈,栈初始为空,支持四种操作:
push x– 向栈顶插入一个数 x;pop– 从栈顶弹出一个数;empty– 判断栈是否为空;query– 查询栈顶元素。
现在要对栈进行 M 个操作,其中的每个操作 33 和操作 44 都要输出相应的结果。
输入格式
第一行包含整数 M,表示操作次数。
接下来 M 行,每行包含一个操作命令,操作命令为 push x,pop,empty,query 中的一种。
输出格式
对于每个 empty 和 query 操作都要输出一个查询结果,每个结果占一行。
其中,empty 操作的查询结果为 YES 或 NO,query 操作的查询结果为一个整数,表示栈顶元素的值。
数据范围
$$
1≤M≤100000\
1≤x≤109
$$
所有操作保证合法。
输入样例:
1 | |
输出样例:
1 | |
思路

此时的top=3,指向的是元素st[3] = 4。
代码
答案(请自己先思考一下再参考)
#include < iostream>
using namespace std;
const int N = 1e5 + 10;
int st[N],top;
int n;
// 初始化栈
void Init()
{
top = -1; // top是栈顶,一开始没有元素,初始化为-1,top指向的就是栈顶部元素的下标,请看上图理解top
}
int main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin >> n;
Init();//1、初始化栈
while (n--)
{
string s;
cin >> s;
if (s == "push") // 入栈
{
int x;
cin >> x;
st[++top] = x;
}
else if (s == "pop") // 出栈
{
top--;
}
else if (s == "empty") // 判断栈是否为空
{
if(top == -1) cout << "YES\n";
else cout << "NO\n";
}
else // 查询栈的顶部元素
{
cout << st[top] << '\n';
}
}
}
二、火车进栈(这道题目大家可以先放着,因为涉及到了后面的一个递归算法,所以不会写也没有很大的关系,简单)
这里有 n 列火车将要进站再出站,但是,每列火车只有 11 节,那就是车头。
这 n 列火车按 1 到 n 的顺序从东方左转进站,这个车站是南北方向的,它虽然无限长,只可惜是一个死胡同,而且站台只有一条股道,火车只能倒着从西方出去,而且每列火车必须进站,先进后出。
也就是说这个火车站其实就相当于一个栈,每次可以让右侧头火车进栈,或者让栈顶火车出站。
下面是火车进站的一种方式的动态图:

现在请你按字典序输出前 20 种可能的出栈方案。
输入格式
输入一个整数 n,代表火车数量。
输出格式
按照《字典序》输出前 20 种答案,每行一种,不要空格。
数据范围
1≤n≤20
输入样例:
1 | |
输出样例:
1 | |
思路
使用最基础的dfs的思想
代码
答案(请自己先思考一下再参考)
#include< iostream>
#include< vector>
using namespace std;
const int N = 2e1 + 5;
int n, remain = 0;
int tt, stk[N];
vector< int> path;
void dfs(int u) {
if (u == n + 1) { // edge:边界
if (++remain > 20) {
exit(0);
}
for (auto x:path) { //输出路径中的
cout << x;
}
// 如果没有数字可用了, 那么输出一下path+栈中的数字
for (int i = tt - 1; i >= 0; i--) { //输出栈中剩下的(后进先出
cout << stk[i];
}
cout << endl;
return;
}
if (tt) {
path.push_back(stk[--tt]);
dfs(u);
stk[tt++] = path.back();
path.pop_back();
}
stk[tt++] = u;
dfs(u + 1);
tt--;
}
int main() {
cin >> n;
dfs(1);
return 0;
}
三、有效括号(简单+)
小刘在大一下学期学习到了数据结构栈操作中的经典例题,但是他不会写,请帮助他编写C++代码解决下列例题。
给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。
示例 1:
1 | |
示例 2:
1 | |
示例 3:
1 | |
提示:
1 | |
注意:s 仅由括号 ‘()[]{}’ 组成
思路
代码中有解释,基本就是按照栈的基本操作思路实现的。
代码
答案(请自己先思考一下再参考)
#include < iostream>
#include < algorithm>
#include < stack>
using namespace std;
int main()
{
string s;
cin >> s;
if(s.size()== 0)
{
cout << "false";
return 0;
}
if(s.size()%2 == 1)
{
cout << "false";
return 0;
}
if(s[0] &&(s[0]== ']' || s[0]== '}'||s[0] == ')' )) {
cout << "false";
return 0;
}
int length = s.size() ;
stack< char> charst ;
char current_deal_char; // 当前处理的字符
for(int i = 0 ;i < length ; i++) {
if(charst.size() == 0 && (s[i]== ']' || s[i]== '}'||s[i] == ')' )){
cout << "false";
return 0;
}
// 如果遇到左括号,入栈
if(s[i] == '(' || s[i] == '{' || s[i] == '['){
charst.push(s[i]) ;
}
else if(s[i]== ']' || s[i]== '}'||s[i] == ')'){
// 如果遇到右括号
char tmp = charst.top() ;
//cout<< tmp << endl;
if(s[i] ==']' && tmp =='[') {
// 如果相等,则抵消
charst.pop() ;
}else if(s[i] == ')' && tmp == '(') {
charst.pop() ;
}else if(s[i] == '}' && tmp == '{') {
charst.pop() ;
}else {
cout << "false";
return 0;
}
}
}
// cout<< charst.size()<< endl;
cout << (charst.empty() == 1 ? "true" : "false");
}