栈(Stack)
简介(Introduction)
限定仅在表尾进行插入和删除操作的线性表,这一端被称为栈顶(Top),另一端称为栈底(Bottom)
描述(Description)
- 栈是一个 先入后出 —— FILO-First In Last Out 的有序列表,先放进去的最后拿出来,而后放入的先拿出来。
- 向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素
- 从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
示例(Example)
代码(Code)
-
入栈
void push(int x) { stk[ ++ tt ] = x;//tt一开始为0 }
-
出栈
void pop() { -- tt; }
-
判断是否栈空
bool empty() { if (tt == 0) return true; return false; }
-
查询栈顶元素
int query() { return stk[tt]; }
应用(Application)
单调栈
给定一个长度为
N
的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出-1
。输入格式
第一行包含整数
N
,表示数列长度。
第二行包含N
个整数,表示整数数列。输出格式
共一行,包含
N
个整数,其中第i
个数表示第i
个数的左边第一个比它小的数,如果不存在则输出-1
。数据范围
\(1 \le N \le 10^5\)
\(1 \le 数列中元素 \le10^9\)
输入样例:
5
3 4 2 7 5
输出样例:
-1 3 -1 2 2
-
题解:
// C++ Version #include <iostream> using namespace std; const int N = 1e6 + 10; int n, tt; int stk[N]; int main() { cin >> n; for (int i = 0; i < n; i ++ ) { int x; cin >> x; while (tt && stk[tt] >= x) tt -- ; // 如果栈顶元素大于当前待入栈元素,则出栈 if (tt) cout << stk[tt] << ' '; // 输出栈顶元素———第一个小于x的值 else cout << "-1" << ' '; // 如果栈空,则没有比该元素小的值 stk[ ++ tt ] = x; } return 0; }
中缀表达式求和
-
分析:先转化为 后缀表达式,然后通过栈进行存储并求和(后缀表达式中忽略了括号)
-
题解:
// C++ Version #include <iostream> #include <unordered_map> #include <stack> using namespace std; //设置优先级 unordered_map<char, int> h = {{'-', 1}, {'+', 1}, {'*', 2}, {'/', 2}}; stack<int> num; // 用于存所有数字 stack<char> op; // 用于存储运算符 void calc() { int b = num.top(); // 取出第二个数 num.pop(); int a = num.top(); // 取出第一个数 num.pop(); int c = op.top(); // 取出一个操作符 op.pop(); int res; //计算结果 if (c == '-') res = a - b; else if (c == '+') res = a + b; else if (c == '*') res = a * b; else if (c == '/') res = a / b; num.push(res); // 将计算后的结果加入结果集 } int main() { string s; cin >> s; for (int i = 0; i < s.size(); i ++ ) { auto c = s[i]; if (isdigit(c)) { // 将数字入栈 int x = 0, j = i; while (j < s.size() && isdigit(s[j])) // 可能出现多位数 x = x * 10 + s[j ++ ] - '0'; num.push(x); // 将 >= 1 位的数添加至num中 i = j - 1; // 更新i的位置移动到多位数的最后一位 } else if (c == '(') op.push(c); // 如果左括号直接加入op else if (c == ')') { // 遇到右括号计算括号里面的 while (op.size() && op.top() != '(') calc(); // 一直计算到左括号的位置 op.pop(); // 将左括号删除 } else { while (op.size() && h[op.top()] >= h[c]) calc(); //根据优先级进行计算 op.push(c); // 将本次的操作符进行入栈 } } while (op.size()) calc(); // 计算所有剩余的数字 cout << num.top() << endl; // 最后一个数即为答案 return 0; }
中缀转后缀表达式
- 题解
#include <iostream> #include <unordered_map> #include <stack> using namespace std; stack<char> op; void calc() { char c = op.top(); op.pop(); cout << c << ' '; } int main() { string s; cin >> s; unordered_map<char, int> pr = {{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}}; for (int i = 0; i < s.size(); i ++ ) { if (isdigit(s[i])) { int j = i, x = 0; while (j < s.size() && isdigit(s[j])) x = x * 10 + s[j ++ ] - '0'; cout << x << ' '; i = j - 1; } else if (s[i] == '(') op.push(s[i]); else if (s[i] == ')') { while (op.size() && op.top() != '(') calc(); op.pop(); } else { while (op.size() && op.top() != '(' && pr[op.top()] >= pr[s[i]]) calc(); op.push(s[i]); } } while (op.size()) calc(); return 0; }