当前位置:   article > 正文

C++表达式求值(利用二叉树和栈分别描述)_利用二叉树求解表达式的值

利用二叉树求解表达式的值

求例如“(123-5)*6+(9-8)*(5-6)-(10-2*(3-9))”这样的表达式的值。

此类问题有两种方法可以解答,第一种是利用二叉树的性质,构建表达树栈。第二种方法是利用两个栈,一个放运算符,一个放数据,通过优先级顺序进行运算操作。

1)利用二叉树描述

     首先建立表达式树栈,把整个表达式按照优先级分解成各个子表达式,把子表达式分配给二叉树的节点构成表达树栈。表达树栈建好之后就可以从根节点开始递归计算表达式的值。表达树栈的建立过程如下:

  

  1. struct expression
  2. {//表达式
  3. char op;
  4. expression* left;
  5. expression* right;
  6. double value;
  7. expression(char theOp):op(theOp),left(nullptr),right(nullptr){ }
  8. expression(double theValue) :value(theValue), op('#') {
  9. left = right = nullptr;
  10. }
  11. };
  12. class expTree
  13. {//表达式树
  14. public:
  15. expTree(const string& str)
  16. {//构造树
  17. int n = str.size() - 1;
  18. GenExpTree(str, 0,n, root);
  19. }
  20. ~expTree() { postOrderErase(root); } //析构树
  21. void postOrderErase(expression* &exp)
  22. {//后序删除
  23. if (exp != nullptr) {
  24. postOrderErase(exp->left);
  25. postOrderErase(exp->right);
  26. delete exp;
  27. }
  28. }
  29. double calculate() { return myCal(root); }
  30. double myCal(expression* &exp)
  31. {
  32. if (exp != nullptr) {
  33. if (exp->op == '#') {
  34. return exp->value;
  35. }
  36. double x = myCal(exp->left);
  37. double y = myCal(exp->right);
  38. switch (exp->op)
  39. {
  40. case'+':return x + y;
  41. case'-':return x -y;
  42. case'*':return x*y;
  43. case'/':return x / y;
  44. }
  45. }
  46. }
  47. private:
  48. expression* root;
  49. void GenExpTree(const string& str, int b, int e, expression* & exp)
  50. {
  51. if (b<e&&str[b] == '(') {//找到和第一个括号相匹配的')'
  52. int i = 0,j=b;
  53. for (; j <= e;j++) {
  54. if (str[j]== '(') {
  55. ++i;
  56. }
  57. else if (str[j]== ')') {
  58. --i;
  59. }
  60. if (i == 0) {
  61. break;
  62. }
  63. }
  64. if (j ==e) {//只有括号是对称的才消除,否则例如()()()这种不能消除
  65. ++b, --e;
  66. }
  67. }
  68. if (b > e) {
  69. exp = nullptr;
  70. return;
  71. }
  72. int brackets = 0;
  73. int lastPS = -1, lastMD = -1;
  74. bool findChar=false;
  75. for (int i = b; i <=e; i++)
  76. {
  77. if (str[i] != '.'&&str[i]<'0' || str[i]>'9') {//非常量
  78. findChar = true;
  79. switch(str[i])
  80. {
  81. case'(': brackets++; break;
  82. case')': brackets--; break;
  83. case'+':
  84. case'-': if(!brackets)lastPS=i; break;
  85. case'*':
  86. case'/': if (!brackets)lastMD=i; break;
  87. }
  88. }
  89. }
  90. if (!findChar) {
  91. exp = new expression(stod(str.substr(b, e - b + 1)));
  92. return;
  93. }
  94. if (lastPS == -1) {
  95. lastPS = lastMD;
  96. }
  97. exp = new expression(str[lastPS]);
  98. GenExpTree(str, b, lastPS - 1, exp->left);
  99. GenExpTree(str, lastPS+1,e, exp->right);
  100. }
  101. };
  102. void testExpression()
  103. {
  104. string str = "(123-5)*6+(9-8)*(5-6)-(10-2*(3+8))+8*(9-1)";
  105. expTree expT(str);
  106. cout << expT.calculate() << endl; //输出783
  107. }

2)利用两个栈来描述

    一个栈用来放运算符,另一个栈用来放数据。基本的思想是,如果运算符栈为空,则直接把运算符添加到运算符栈,否则,要比较栈外和栈内的运算符优先级,如果栈内的运算符优先级高(包括栈内的运算符和栈外的运算符处于一个优先级,也认为是栈内的优先级高)则把栈内运算符弹出,再把弹出两个数据符进行运算,把结果再次压入数据符栈,当然新来的运算符也要入运算符栈。如果栈外的运算符高,则直接把运算符压入运算符栈。如果遇见了‘)’,则说明有一对括号了,此时要把括号里的值计算好,把结果压入数据栈,当然‘)’不入栈,而且要把之前的‘(’删除。最后如果遍历过程中遇见的是数据符,则直接查找长度,把持续的数据先进行数据转换stod,再把结果压入数据栈。遍历完成后,也许因为优先级的关系,有些数据还没计算,此时的运算优先级是完全按照栈的出栈顺序来的,因此直接出栈计算,直到运算符栈为空,此时的数据栈也只剩一个元素就是最后的计算结果,返回此唯一的栈顶元素。

         

  1. int priority(char a, char b)
  2. {//a表示栈内的运算符,b表示栈外的运算符
  3. if (b == '+' || b == '-' )
  4. {
  5. if (a == '+' || a == '-' || a == '*' || a == '/') {//栈内的优先级高
  6. return 1;
  7. }
  8. else if (a == '(') {//栈外的优先级高
  9. return -1;
  10. }
  11. }
  12. else if (b == '*' || b == '/') {
  13. if (a == '*' || a == '/') {//栈内的优先级高
  14. return 1;
  15. }
  16. else if (a == '+' || a == '-' || a == '(') {//栈外的优先级高
  17. return -1;
  18. }
  19. }
  20. else if (b == '(') {//栈外的优先级高
  21. return -1;
  22. }
  23. return 0;
  24. }
  25. double calculate(double x, char op, double y)
  26. {
  27. switch (op)
  28. {
  29. case '+':return x + y;
  30. case '-':return x - y;
  31. case '*':return x * y;
  32. case '/':return x / y;
  33. }
  34. }
  35. double expStack(const string& str)
  36. {
  37. stack<char> opor;
  38. stack<double>opnd;
  39. int i = 0;
  40. while (i < str.size()) {
  41. if (str[i] != '.'&&str[i]<'0' || str[i]>'9') {
  42. if (opor.empty() || priority(opor.top(), str[i]) < 0) {//栈外优先级高
  43. opor.push(str[i]);
  44. }
  45. else if (priority(opor.top(),str[i]) > 0) {//栈内优先级高
  46. double a = opnd.top();
  47. opnd.pop();
  48. double b = opnd.top();
  49. opnd.pop();
  50. opnd.push(calculate(b, opor.top(), a));
  51. opor.pop();
  52. opor.push(str[i]);
  53. }
  54. else if (str[i] == ')') {//计算括号里的值
  55. while (opor.top() != '(') {
  56. double a = opnd.top();
  57. opnd.pop();
  58. double b = opnd.top();
  59. opnd.pop();
  60. opnd.push(calculate(b, opor.top(), a));
  61. opor.pop();
  62. }
  63. opor.pop();
  64. }
  65. ++i;
  66. }
  67. else {//常量
  68. int k = i;
  69. while (str[i] == '.' || str[i] >= '0'&&str[i] <='9') {
  70. i++;
  71. }
  72. opnd.push(stod(str.substr(k, i - k)));
  73. }
  74. }
  75. //计算剩余的数
  76. while (!opor.empty()) {
  77. double a = opnd.top();
  78. opnd.pop();
  79. double b = opnd.top();
  80. opnd.pop();
  81. opnd.push(calculate(b, opor.top(),a));
  82. opor.pop();
  83. }
  84. return opnd.top();
  85. }
  86. void testExpression()
  87. {
  88. string str = "(123-5)*6+(9-8)*(5-6)-(10-2*(3+8))+8*(9-1)";
  89. //string str = "(9-7)*(5-6)";
  90. //string str = "4+3*(5+2/1)";
  91. cout << expStack(str) << endl; //输出783
  92. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/390115
推荐阅读
相关标签
  

闽ICP备14008679号