学习顺序:

  1. 学会使用STL的基本用法
  2. 学会使用STL解决问题
  3. 学会用一维数组模拟栈,解决问题

栈是只能在某一端插入和删除的特殊线性表

stack stk

  1. stack<int> s;
  2. s.push(3);
  3. s.push(2);
  4. s.push(5);
  5. cout << s.top(); // 5
  6. s.pop();
  7. cout << s.top(); // 2

一维数组模拟栈

https://www.acwing.com/problem/content/830/
image.png
image.png

  1. // tt指针初始化为0,第一个数存在1上,当tt==0的时候,代表空栈
  2. #include <iostream>
  3. using namespace std;
  4. const int N = 1e5 + 10;
  5. int stk[N];
  6. int tt = 0;
  7. int main()
  8. {
  9. int M;
  10. cin >> M;
  11. string op;
  12. int x;
  13. while (M--)
  14. {
  15. cin >> op;
  16. if (op == "push")
  17. {
  18. cin >> x;
  19. stk[++tt] = x;
  20. }
  21. if (op == "pop")
  22. {
  23. tt--;
  24. }
  25. if (op == "empty")
  26. {
  27. if (tt == 0) cout << "YES" << endl;
  28. else cout << "NO" << endl;
  29. }
  30. if (op == "query")
  31. {
  32. cout << stk[tt] << endl;
  33. }
  34. }
  35. return 0;
  36. }

例题,【例1-2】后缀表达式的值

  1. //用一个栈维护数字,用一个栈维护运算符
  2. //这道题目没有括号,另外注意运算数的数值范围比较大
  3. //不开LL见祖宗

例题,表达式括号匹配(stack)

  1. //用一个栈维护左括号和右括号的关系
  2. //右括号,没有左括号配对就是非法
  3. //左括号,最后没有右括号配对就是非法

例题,车厢调度(train)

  1. //第一种方法,把一系列车厢,当成一个数组,1, 2, 3, 4, ..., n
  2. //x读进来了,那么,我们就要认为:x之后的数字,都不应该出现在栈中;x之前的数字没入栈的都应该入栈
  3. //标记在不在栈里的方法,1代表在栈里面,2代表已经出栈
  4. //第二种方法,用一个stack硬来模拟这个进出栈的过程(冷不丁让我重写,我想我是模拟不出来的)
  5. //如果stack空的,把前面没入栈的入栈
  6. //如果stack非空,栈顶元素如果比我大,那是非法的;
  7. //整个过程中,用一个变量tp,初始值设为1,来维护栈顶元素的值

例题,中缀表达式值(expr)

  1. //在这道题目上,我一共花费了4个小时
  2. //所以,我建议你自己做,研究至少花费2个小时。
  3. //可以很好的提升代码能力,加深对栈的理解,对表达式的理解
  4. //第一种方法,直接利用中缀表达式,进行求解,这个方法和前面的题目类似
  5. //第二种方法,中缀读进来,然后转成后缀
  6. //后缀的建立,用一个queue<node>进行维护,node可以是运算数,也可以是运算符
  7. //node需要使用struct定义一下
  8. //关于非法情况的判断
  9. //首先这道题目的数据,没有那么严格,不需要判断除数不能为0的情况
  10. //其他非法,左右括号不匹配问题;只有一位,这一位还是运算符; 上来第一位是+*/运算符,负号是可以的
  11. //中缀表达式,两个运算符连在一块了;右括号没有左括号匹配,左括号没有右括号匹配
  12. //网上能搜到题解,对左括号个数和右括号个数相同作为配对的原则,这个其实不严谨
  13. //运算符优先级,可以写一个函数实现,也可以写一个map预设好

例题,P1981 [NOIP2013 普及组] 表达式求值

  1. #include <iostream>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <stack>
  5. #include <unordered_map>
  6. using namespace std;
  7. const int MOD = 10000;
  8. stack<int> num;
  9. stack<char> op;
  10. void eval()
  11. {
  12. int b = num.top(); num.pop();
  13. int a = num.top(); num.pop();
  14. char c = op.top(); op.pop();
  15. if (c == '+') num.push((a + b) % MOD);
  16. else num.push(a * b % MOD);
  17. }
  18. int main()
  19. {
  20. string s;
  21. cin >> s;
  22. unordered_map<char, int> pr{{'+', 1}, {'*', 2}};
  23. for (int i = 0; i < s.size(); i ++ )
  24. {
  25. if (isdigit(s[i]))
  26. {
  27. int j = i, x = 0;
  28. while (j < s.size() && isdigit(s[j])) x = x * 10 + s[j ++ ] - '0';
  29. num.push(x % MOD);
  30. i = j - 1;
  31. }
  32. else
  33. {
  34. while (op.size() && pr[op.top()] >= pr[s[i]]) eval();
  35. op.push(s[i]);
  36. }
  37. }
  38. while (op.size()) eval();
  39. cout << num.top() << endl;
  40. return 0;
  41. }
  42. // 以后的习题中,会涉及一个表示式树的题目