我们使用两个栈,就能对四则运算表达式进行求值:一个栈存数据,一个栈存运算符。

顶部求值

首先考虑一个最简单的例子,即表达式3 + 4。将数字压入 number stack,将运算符压入 operator stack。然后弹出两个数字和运算符,用运算符结合两个数字,并将结果压入栈中。

1.jpg

此操作是该算法的基础:顶部求值

优先级

在代数运算中,每个运算符都有优先级。在四则运算下,我们先* /,后+ -

考虑表达式3 * 4 + 5,如下是它的处理步骤:

2.jpg

因为*+优先级高,故对其顶部求值

3.jpg


对于表达式3 + 4 * 5我们的操作过程如下:

4.jpg
5.jpg
6.jpg

括号

现在我们的表达式加入了括号3 * (4 + 5)。首先一个左括号(被压入 operator stack,接着运算符+也被压入。当遇到右括号)时,我们就可以顶部求值了。整个过程如下:

7.jpg

算法描述

  1. if you read a number:
  2. Push it on the number stack;
  3. else if you read a '(':
  4. Push it on the operator stack;
  5. else if you read an operator 'op':
  6. while precedence( top of operator stack ) >= precedence(op):
  7. Evaluate the top;
  8. Push 'op' on the operator stack;
  9. else if you read a ')':
  10. while the top of the stack if not a '(':
  11. Evaluate the top;
  12. Pop the '(';
  13. else if there is no more input:
  14. while the operator stack is not empty:
  15. Evaluate the top;

Cpp 代码实现

  1. #include <iostream>
  2. #include <sstream>
  3. #include <stack>
  4. #include <string>
  5. #include <vector>
  6. static void eval_top(std::stack<double> &num_stack,
  7. std::stack<char> &op_stack) {
  8. double arg2 = num_stack.top();
  9. num_stack.pop();
  10. double arg1 = num_stack.top();
  11. num_stack.pop();
  12. char op = op_stack.top();
  13. op_stack.pop();
  14. switch (op) {
  15. case '+':
  16. num_stack.push(arg1 + arg2);
  17. return;
  18. case '-':
  19. num_stack.push(arg1 - arg2);
  20. return;
  21. case '*':
  22. num_stack.push(arg1 * arg2);
  23. return;
  24. case '/':
  25. if (arg2 == 0) {
  26. std::fprintf(stderr, "divisior can not be zero!\n");
  27. std::exit(1);
  28. }
  29. num_stack.push(arg1 / arg2);
  30. return;
  31. }
  32. std::fprintf(stderr, "Unknown character ...\n");
  33. }
  34. static std::vector<std::string> split_string(std::string &input,
  35. char delimeter) {
  36. std::istringstream in(input); // turn string into input stream
  37. std::string tmp;
  38. std::vector<std::string> symbol_list;
  39. while (std::getline(in, tmp, ' ')) {
  40. symbol_list.push_back(tmp);
  41. }
  42. return symbol_list;
  43. }
  44. double eval_expression(std::string &input) {
  45. if (input.empty()) {
  46. std::fprintf(stderr, "EMPTY INPUT!\n");
  47. return 0;
  48. }
  49. // Split symbols by white space
  50. std::vector<std::string> symbol_list = split_string(input, ' ');
  51. std::stack<double> number_stack;
  52. std::stack<char> operator_stack;
  53. for (auto i : symbol_list) {
  54. char ch = *(i.c_str());
  55. if (ch == '(') {
  56. operator_stack.push(ch);
  57. } else if (ch == '+' || ch == '-' || ch == '*' || ch == '/') {
  58. if (operator_stack.empty()) {
  59. operator_stack.push(ch);
  60. continue;
  61. }
  62. // while precedence(top of operator stack) >= precedence(ch)
  63. // We eval_top
  64. char top_op = operator_stack.top();
  65. if (((ch == '+' || ch == '-') &&
  66. (top_op == '*' || top_op == '/')) ||
  67. ((ch == '*' || ch == '/') &&
  68. (top_op == '*' || top_op == '/')) ||
  69. ((ch == '+' || ch == '-') &&
  70. (top_op == '+' || top_op == '-'))) {
  71. eval_top(number_stack, operator_stack);
  72. }
  73. operator_stack.push(ch);
  74. } else if (ch == ')') {
  75. while (operator_stack.top() != '(') {
  76. eval_top(number_stack, operator_stack);
  77. }
  78. operator_stack.pop();
  79. } else {
  80. if (ch == ' ') {
  81. continue;
  82. }
  83. number_stack.push(std::stof(i));
  84. }
  85. }
  86. while (!operator_stack.empty()) {
  87. eval_top(number_stack, operator_stack);
  88. }
  89. return number_stack.top();
  90. }
  91. int main() {
  92. std::string input;
  93. input = "3 + 4"; // output: 7
  94. std::cout << eval_expression(input) << std::endl;
  95. input = "3 * 4 + 5"; // output: 17
  96. std::cout << eval_expression(input) << std::endl;
  97. input = "3 + 4 * 5"; // output: 23
  98. std::cout << eval_expression(input) << std::endl;
  99. input = "3 * ( 4 + 5 )"; // output: 27
  100. std::cout << eval_expression(input) << std::endl;
  101. input = "9 + ( 3 - 1 ) * 3 + 10 / 2"; // output: 20
  102. std::cout << eval_expression(input) << std::endl;
  103. input = "2 / 0"; // divisior can not be zero!
  104. std::cout << eval_expression(input) << std::endl;
  105. return 0;
  106. }