简介

如果理解了 vector,再学习接下来的栈和队列就会比较轻松。

STL 栈 ( std::stack ) 是一种后进先出 (Last In, First Out) 的容器适配器,仅支持查询或删除最后一个加入的元素(栈顶元素),不支持随机访问,且为了保证数据的严格有序性,不支持迭代器

概念不好理解,但是总结出 stack 重要的 3 个方法,其实就对应着简单的数组操作。

  • push : 在数组末尾插入元素
  • top: 获取数组末尾的元素
  • pop: 删除末尾的元素

为了帮助理解,可以用 vector 模拟栈的行为。

  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. template <typename T>
  5. class stack {
  6. private:
  7. vector<int> data;
  8. public:
  9. void push(T value) {
  10. data.push_back(value);
  11. }
  12. T top() {
  13. return data.back();
  14. }
  15. void pop() {
  16. data.pop_back();
  17. }
  18. bool empty() {
  19. return data.size() == 0;
  20. }
  21. };
  22. int main() {
  23. stack<int> s;
  24. for (int i = 0; i < 5; ++i) {
  25. s.push(i);
  26. }
  27. while (!s.empty()) {
  28. cout << s.top() << ' '; // Output: 4 3 2 1 0
  29. s.pop();
  30. }
  31. return 0;
  32. }

使用

导入 <stack> 头文件,体验一下 STL 提供的栈:(其实和自己写的也没什么区别)

  1. #include <iostream>
  2. #include <vector>
  3. #include <stack>
  4. using namespace std;
  5. int main() {
  6. stack<int> s;
  7. for (int i = 0; i < 5; ++i) {
  8. s.push(i);
  9. }
  10. while (!s.empty()) {
  11. cout << s.top() << ' ';
  12. s.pop();
  13. }
  14. return 0;
  15. }

综合案例

利用 逆波兰表达式 求解表达式

  1. #include <iostream>
  2. #include <stack>
  3. #include <string>
  4. #include <vector>
  5. using namespace std;
  6. void calc(stack<int> &nums, stack<char> &ops) {
  7. int y = nums.top();
  8. nums.pop();
  9. int x = nums.top();
  10. nums.pop();
  11. char op = ops.top();
  12. ops.pop();
  13. if (op == '+')
  14. nums.push(x + y);
  15. else if (op == '-')
  16. nums.push(x - y);
  17. else if (op == '*')
  18. nums.push(x * y);
  19. else
  20. nums.push(x / y);
  21. }
  22. // 运算符优先级
  23. int p(char op) {
  24. if (op == '*' || op == '/') return 1;
  25. return 0; // + -
  26. }
  27. int main() {
  28. // string s = "9 + (3 - 1) * 3 + 10 / 2";
  29. string s = "1+(2*3-6/4*(2-1))*5";
  30. stack<int> nums;
  31. stack<char> ops;
  32. int i = 0, n = s.size();
  33. while (i < n) {
  34. if (s[i] == ' ') {
  35. ++i;
  36. continue;
  37. }
  38. if (isdigit(s[i])) {
  39. int num = s[i++] - '0';
  40. while (i < n && isdigit(s[i])) {
  41. num = num * 10 + s[i++] - '0';
  42. }
  43. nums.push(num);
  44. } else if (s[i] == '(') {
  45. ops.push(s[i++]);
  46. } else if (s[i] == ')') {
  47. while (ops.top() != '(') {
  48. calc(nums, ops);
  49. }
  50. ops.pop(); // pop '('
  51. ++i;
  52. } else {
  53. if (ops.empty() || ops.top() == '(') {
  54. ops.push(s[i++]);
  55. } else {
  56. while (!ops.empty() && ops.top() != '(' && p(s[i]) <= p(ops.top())) {
  57. calc(nums, ops);
  58. }
  59. ops.push(s[i++]);
  60. }
  61. }
  62. }
  63. while (!ops.empty()) {
  64. calc(nums, ops);
  65. }
  66. cout << nums.top() << endl;
  67. return 0;
  68. }

思路二:递归处理括号

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. // string s = "9+(3-1)*3+10/2";
  4. char s[1000];
  5. int i = 0, len;
  6. // priority
  7. int level(char op) {
  8. if (op == '*' || op == '/') return 2;
  9. return 1;
  10. }
  11. void pop(stack<int> &nums, stack<char> &ops) {
  12. int y = nums.top();
  13. nums.pop();
  14. int x = nums.top();
  15. nums.pop();
  16. char op = ops.top();
  17. ops.pop();
  18. if (op == '+')
  19. nums.push(x + y);
  20. else if (op == '-')
  21. nums.push(x - y);
  22. else if (op == '*')
  23. nums.push(x * y);
  24. else
  25. nums.push(x / y);
  26. }
  27. int calc() {
  28. // number stack
  29. stack<int> nums;
  30. // operator stack
  31. stack<char> ops;
  32. while (i < len && s[i] != ')') {
  33. if (isdigit(s[i])) {
  34. int num = s[i] - '0';
  35. while (isdigit(s[++i])) {
  36. num = num * 10 + s[i] - '0';
  37. }
  38. nums.push(num);
  39. } else if (s[i] == '(') {
  40. ++i; // skip '('
  41. int sub = calc();
  42. nums.push(sub);
  43. ++i; // skip ')'
  44. } else {
  45. while (!ops.empty() && level(s[i]) <= level(ops.top()))
  46. pop(nums, ops);
  47. ops.push(s[i]);
  48. ++i; // skip current operator
  49. }
  50. }
  51. while (!ops.empty())
  52. pop(nums, ops);
  53. return nums.top();
  54. }
  55. int main() {
  56. cin >> s;
  57. len = strlen(s);
  58. cout << calc() << endl;
  59. return 0;
  60. }