详解如何将中缀表达式转化为后缀表达式

原文地址:详解如何将中缀表达式转化为后缀表达式


本文我将从两种角度来解析如何将中缀表达式转化为后缀表达式

一、从应对考试角度来(在最快的时间内得出最准确的答案)

首先我们应该知道,要想将中缀转化为后缀,需要借助堆栈实现。(不准备画图了,画图有点浪费时间)我会用最简单明了的语言使读者弄懂。[举个例子吧:比如将:2*(9+6/3-5)+4转化为后缀表达式2 9 6 3 / +5 -  * 4 +    ]

1、任何中缀表达式都由运算数,运算符,括号(大,中,小),这三部分组成。

2、从中缀表达式的左边开始扫描(脑中自己想像的),若遇到运算数时,则直接将其输出(不压入堆栈)。

3、若遇到左括号,则将其压栈。

4、若遇到右括号,表达括号内的中缀表达式已经扫描完毕。这时需将栈顶的运算符依次弹出并输出,直至遇到左括号[左括号弹出但不输出]。

5、若遇到的是运算符:a、如果该运算符的优先级大于栈顶运算符的优先级时,将其压栈

                                    b、如果该运算符的优先级小于栈顶运算符的优先级时,将栈顶运算符弹出并输出,接着和新的栈顶运算 符比较,若大于,则将其压栈,若小于,继续将栈顶运算符弹出并输出......(一直递归下去,直至运算符大于栈顶云算符为止)。

6、最后一步,若扫描到中缀表达式的末尾[即扫描结束],若堆栈中还有存留的运算符依次弹出并输出即可。

肯定有一些读者还是没完全弄懂(毕竟全都是文字)。接下来,举一个例子:帮助大家消化

(1)out:2                                                                          stack:

(2)out:2                                                                          stack:*

(3)out:2                                                                          stack: *  (

(4)out:2    9                                                                    stack :*   (

(5)out:2    9                                                                    stack :*   ( +     注:在堆栈中括号的优先级最低

(6)out:2    9   6                                                               stack :*   ( +

(7)out :2   9   6                                                               stack :*   ( +   /

(8)out :2   9   6    3                                                         stack :*   ( +  /

(9)out :2   9   6   3    /                                                     stack :*   ( +   

(10)out: 2   9   6   3    /   +                                              stack : *     (   

(11)out:2   9   6  3   /    +                                                stack : *     (   -

(12)out : 2    9   6  3   /    +   5                                           stack : *    ( -   遇到了右括号

(13)out:2   9   6  3   /   +    5   -                                       stack:*   (      

(14)out:2  9   6   3   /   +    5   -                                       stack:*

(15)out:2  9   6   3   /   +   5    -                                       stack :*    括号弹出但不输出

(16)out :2   9    6   3   /   +   5   -   *                                 stack  :           遇到了+

(17)out:2   9  6   3   /  +   5   -    *                                    stack :+

(18)out:2  9  6   3   /  +   5  -    *   4                                 stack  : +

(19)out:2   9   6   3   /  +  5  -  *  4  +                              stack :      


终于结束了,写到我要吐。注:红笔标记的地方很重要,虽然步骤比较多,当是写起来非常快。至此第一种方法结束。接下来我会用程序实现将中缀表达式转化为后缀表达式,并通过后缀表达式来求值。

------------------------------------------------------------------------------------------------------------------------------------

中缀转后缀表达式的代码如下:(注意代码实现的是多位整数的转化,没有实现小数的转化,通过多位整数的转化理解下原理,小数转化自然就

不难写了)


  
  
  1. /*
  2. 中缀转后缀C++代码实现(比较方便)
  3. 1.遇到操作数:添加到后缀表达式中或直接输出
  4. 2.栈空时:遇到运算符,直接入栈
  5. 3.遇到左括号:将其入栈
  6. 4.遇到右括号:执行出栈操作,输出到后缀表达式,直到弹出的是左括号
  7. 注意:左括号不输出到后缀表达式
  8. 5.遇到其他运算符:弹出所有优先级大于或等于该运算符的栈顶元素,然后将该运算符入栈
  9. 6.将栈中剩余内容依次弹出后缀表达式
  10. */
  11. #include<iostream>
  12. #include<stack>
  13. #include<queue>
  14. #include<map>
  15. #include<string>
  16. #include<cstdio>
  17. #define MAX 100
  18. using namespace std;
  19. //设置优先级(注意默认操作数的优先级最高,即其不需要进栈,进栈的都是运算符)
  20. map< char, int> p;
  21. //一些初始化********************************************
  22. struct Node{
  23. double num; //操作数
  24. char op; //操作符
  25. bool flag; //true表示操作数,false表示操作符
  26. };
  27. typedef struct Node node;
  28. stack<node> s; //操作符栈
  29. queue<node> q; //后缀表达式队列
  30. //******************************************************
  31. void change(string str){
  32. node temp;
  33. for ( int i = 0; i < str.length();){
  34. if (str[i] == '('){ //3.遇到左括号:将其入栈
  35. temp.flag = false;
  36. temp.op = str[i];
  37. s.push(temp);
  38. i++;
  39. } else if (str[i] == ')'){ //4.遇到右括号:执行出栈操作,输出到后缀表达式,直到弹出的是左括号
  40. while (!s.empty() && s.top().op != '('){
  41. q.push(s.top());
  42. s.pop();
  43. }
  44. s.pop(); //弹出左括号
  45. i++;
  46. } else if (str[i] >= '0'&&str[i] <= '9'){
  47. //如果是数字
  48. temp.flag = true;
  49. temp.num = str[i] - '0';
  50. i++; //后移一位,因为数字不一定是个位数
  51. while (i < str.length() && str[i] >= '0'&&str[i] <= '9'){
  52. temp.num = temp.num * 10 + (str[i] - '0');
  53. i++;
  54. }
  55. q.push(temp); //操作数进入后缀表达式
  56. } else{
  57. //如果是操作符
  58. //5.遇到其他运算符:弹出所有优先加大于或等于该运算符的栈顶元素,然后将该运算符入栈
  59. temp.flag = false;
  60. while (!s.empty() && p[s.top().op]>=p[str[i]]){
  61. q.push(s.top());
  62. s.pop();
  63. }
  64. temp.op = str[i];
  65. s.push(temp);
  66. i++;
  67. }
  68. }
  69. //6.将栈中剩余内容依次弹出后缀表达式
  70. while (!s.empty()){
  71. q.push(s.top());
  72. s.pop();
  73. }
  74. }
  75. int main()
  76. {
  77. node cur;
  78. string str;
  79. p[ '+'] = p[ '-'] = 1; //通过hashmap赋值
  80. p[ '*'] = p[ '/'] = 2;
  81. cin >> str;
  82. change(str);
  83. while (!q.empty()){
  84. cur = q.front();
  85. if (cur.flag == true) cout << cur.num<< " ";
  86. else cout << cur.op<< " ";
  87. q.pop();
  88. }
  89. return 0;
  90. }

后缀表达式求值代码(将之前的稍作修改了,添加了calculate函数来计算结果)

原理:从左到右扫描后缀表达式,如果是操作数,压栈,若是操作符,将弹出两个操作数,进行计算,计算的结果再压入栈中,最后栈顶的元素就是所要的值。


  
  
  1. /*
  2. 中缀转后缀C++代码实现(比较方便)
  3. 1.遇到操作数:添加到后缀表达式中或直接输出
  4. 2.栈空时:遇到运算符,直接入栈
  5. 3.遇到左括号:将其入栈
  6. 4.遇到右括号:执行出栈操作,输出到后缀表达式,直到弹出的是左括号
  7. 注意:左括号不输出到后缀表达式
  8. 5.遇到其他运算符:弹出所有优先级大于或等于该运算符的栈顶元素,然后将该运算符入栈
  9. 6.将栈中剩余内容依次弹出后缀表达式
  10. */
  11. #include<iostream>
  12. #include<stack>
  13. #include<queue>
  14. #include<map>
  15. #include<string>
  16. #include<cstdio>
  17. #define MAX 100
  18. using namespace std;
  19. //设置优先级(注意默认操作数的优先级最高,即其不需要进栈,进栈的都是运算符)
  20. map< char, int> p;
  21. //一些初始化********************************************
  22. struct Node{
  23. double num; //操作数
  24. char op; //操作符
  25. bool flag; //true表示操作数,false表示操作符
  26. };
  27. typedef struct Node node;
  28. stack<node> s; //操作符栈
  29. stack<node> s1; //存放操作数的,为了计算后缀表达式的值
  30. queue<node> q; //后缀表达式队列
  31. //******************************************************
  32. //中缀转后缀函数
  33. void change(string str){
  34. node temp;
  35. for ( int i = 0; i < str.length();){
  36. if (str[i] == '('){ //3.遇到左括号:将其入栈
  37. temp.flag = false;
  38. temp.op = str[i];
  39. s.push(temp);
  40. i++;
  41. }
  42. else if (str[i] == ')'){ //4.遇到右括号:执行出栈操作,输出到后缀表达式,直到弹出的是左括号
  43. while (!s.empty() && s.top().op != '('){
  44. q.push(s.top());
  45. s.pop();
  46. }
  47. s.pop(); //弹出左括号
  48. i++;
  49. }
  50. else if (str[i] >= '0'&&str[i] <= '9'){
  51. //如果是数字
  52. temp.flag = true;
  53. temp.num = str[i] - '0';
  54. i++; //后移一位,因为数字不一定是个位数
  55. while (i < str.length() && str[i] >= '0'&&str[i] <= '9'){
  56. temp.num = temp.num * 10 + (str[i] - '0');
  57. i++;
  58. }
  59. q.push(temp); //操作数进入后缀表达式
  60. }
  61. else{
  62. //如果是操作符
  63. //5.遇到其他运算符:弹出所有优先加大于或等于该运算符的栈顶元素,然后将该运算符入栈
  64. temp.flag = false;
  65. while (!s.empty() && p[s.top().op] >= p[str[i]]){
  66. q.push(s.top());
  67. s.pop();
  68. }
  69. temp.op = str[i];
  70. s.push(temp);
  71. i++;
  72. }
  73. }
  74. //6.将栈中剩余内容依次弹出后缀表达式
  75. while (!s.empty()){
  76. q.push(s.top());
  77. s.pop();
  78. }
  79. }
  80. //*************************************************************
  81. //后缀表达式的计算
  82. /*
  83. 从左到右扫描后缀表达式
  84. 1)若是操作数,就压栈,
  85. 2)若是操作符,就连续弹出两个操组数
  86. 3)栈顶的值即为所需结果
  87. 注:先弹出的是第一操作数,后弹出的是第二操作数
  88. */
  89. double calculate(){
  90. double num_a, num_b; //操作数a,b
  91. node cur, temp;
  92. while (!q.empty()){ //后缀队列非空
  93. cur = q.front(); //记录队首元素
  94. q.pop();
  95. if (cur.flag == true){ //是操作数进入栈
  96. s1.push(cur);
  97. }
  98. else{ //是操作符就运算
  99. num_b = s1.top().num;
  100. s1.pop(); //弹出第二操作数
  101. num_a = s1.top().num;
  102. s1.pop(); //弹出第一操作数
  103. temp.flag = true;
  104. if (cur.op == '+'){
  105. temp.num = num_a + num_b;
  106. }
  107. else if (cur.op == '-'){
  108. temp.num = num_a - num_b;
  109. }
  110. else if (cur.op == '*'){
  111. temp.num = num_a * num_b;
  112. }
  113. else{
  114. temp.num = num_a / num_b;
  115. }
  116. s1.push(temp); //把计算后的结果再次压栈
  117. }
  118. }
  119. return s1.top().num;
  120. }
  121. //*************************************************************
  122. int main()
  123. {
  124. string str;
  125. p[ '+'] = p[ '-'] = 1; //通过hashmap赋值
  126. p[ '*'] = p[ '/'] = 2;
  127. cin >> str;
  128. change(str);
  129. //*****************************************************
  130. //中缀转后缀
  131. /*while (!q.empty()){
  132. cur = q.front();
  133. if (cur.flag == true) cout << cur.num << " ";
  134. else cout << cur.op << " ";
  135. q.pop();
  136. }*/
  137. while (!s1.empty()){ //初始化栈s1
  138. s1.pop();
  139. }
  140. double answer=calculate();
  141. cout << answer<< endl;
  142. return 0;
  143. }


完!

注:要输入合法的表达式,不然会出错。代码中没有写当输入非法表达式时的处理情况。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值