• 数据结构Java实现06----中缀表达式转换为后缀表达式


    本文主要内容:

    • 表达式的三种形式
    • 中缀表达式与后缀表达式转换算法

    一、表达式的三种形式:

    • 中缀表达式:运算符放在两个运算对象中间,如:(2+1)*3。我们从小做数学题时,一直使用的就是中缀表达式。
    • 后缀表达式:不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则),如:2 1 + 3 *。又比如3+(6-4/2)*5=23的后缀表达式为:3642/-5*+# (#符号为结束符)
    • 前缀表达式:同后缀表达式一样,不包含括号,运算符放在两个运算对象的前面,如:* + 2 1 3 。前缀表达式和后缀表达式其实是差不多的,只不过符号位置不同而已,前缀表达式不是很常见。

    二、中缀表达式转换为后缀表达式:(思路)

    1、将中缀表达式转换为后缀表达式:(步骤,有点难理解)

    (1)当读到数字直接送至输出队列中;

    (2)当读到运算符t时:

      a.将栈中所有优先级高于或等于t的运算符弹出,送到输出队列中;

        注:这句话不好理解,可以说成这样,从栈顶开始,依次弹出比当前处理的运算符优先级高的运算符,直到一个比它优先级低的或者遇到了一个左括号就停止

      b.t进栈;

    (3)读到左括号时总是将它压入栈中;

    (4)读到右括号时,将靠近栈顶的第一个左括号上面的运算符全部依次弹出,送至输出队列后,再丢弃左括号;

    (5)中缀表达式全部读完后,若栈中仍有运算符,将其送到输出队列中。

     

    举例:

    124b3dd7-f3b3-4110-904c-8a2b1d85dccd

    上图中,左侧的那一列为输出序列,右侧的那一列为栈。

    2、运用后缀表达式进行计算:

      (1)建立一个栈S;

      (2)从左到右读后缀表达式,读到数字就将它转换为数值压入栈S中,读到运算符则从栈中依次弹出两个数分别到Y和X,然后以“X 运算符 Y”的形式计算机出结果,再压加栈S中;

      (3)如果后缀表达式未读完,就重复上面过程,最后输出栈顶的数值则为结束。

    举例:

    3+(2-5)*6/3=-3 ,其后缀表达式为:325-6*3/+。其运算结果如下:

    45270e43-7c61-4ac2-af8f-efb437e8d742

    三、代码实现:将中缀表达式转换为后缀表达式

    • JDK  Stack类使用
    • 使用泛型

    代码实现:

    (1)StringToArithmetic.java:(中缀表达式转化为后缀表达式的工具类

      1 /**
      2  * Created by smyhvae on 2015/9/7.
      3  * 工具类:
      4  * 1、中缀表达式转化为后缀表达式
      5  * 2、给出一个算术表达式(中缀表达式),直接得到计算结果
      6  */
      7 
      8 import java.util.Stack;
      9 import java.util.regex.Pattern;
     10 
     11 public class StringToArithmetic {
     12 
     13     private StringToArithmetic() {
     14     }
     15 
     16     //方法:给出一个算术表达式(中缀表达式),得到计算结果。 例如 (5+8+10)*1,返回23
     17     public static double stringToArithmetic(String string) {
     18         return suffixToArithmetic(infixToSuffix(string));
     19     }
     20 
     21     /**
     22      * 中缀表达式转后缀表达式 只处理了+,-,*,/和括号,没有处理负号及其它运算符,也没对前缀表达式验证。
     23      * 如要处理负号,可对表达式进行预转义处理,当下面条件成立时,将负号换成单目运算符"!" infix.charAt[i]=='-'&&(
     24      * i==0||infix.charAt[i-1]=='(')
     25      * 3*6/4+3
     26      * 3+6-4           3 6 + 4 -
     27      * 3+(6-4/2)*5    3 6 4 2 / - 5 * +
     28      */
     29     //方法:中缀表达式转成后缀表达式
     30     public static String infixToSuffix(String infix) {
     31         Stack<Character> stack = new Stack<Character>();
     32         String suffix = "";
     33         int length = infix.length();
     34         for (int i = 0; i < length; i++) {
     35             Character temp;
     36             char c = infix.charAt(i);
     37             switch (c) {
     38                 // 忽略空格
     39                 case ' ':
     40                     break;
     41                 // 碰到'(',push到栈
     42                 case '(':
     43                     stack.push(c);
     44                     break;
     45                 // 碰到'+''-',将栈中所有运算符弹出,送到输出队列中
     46                 case '+':
     47                 case '-':
     48                     while (stack.size() != 0) {
     49                         temp = stack.pop();
     50                         if (temp == '(') {
     51                             stack.push('(');
     52                             break;
     53                         }
     54                         suffix += " " + temp;
     55                     }
     56                     stack.push(c);
     57                     suffix += " ";
     58                     break;
     59                 // 碰到'*''/',将栈中所有乘除运算符弹出,送到输出队列中
     60                 case '*':
     61                 case '/':
     62                     while (stack.size() != 0) {
     63                         temp = stack.pop();
     64                         if (temp == '(' || temp == '+' || temp == '-') {
     65                             stack.push(temp);
     66                             break;
     67                         } else {
     68                             suffix += " " + temp;
     69                         }
     70                     }
     71                     stack.push(c);
     72                     suffix += " ";
     73                     break;
     74                 // 碰到右括号,将靠近栈顶的第一个左括号上面的运算符全部依次弹出,送至输出队列后,再丢弃左括号
     75                 case ')':
     76                     while (stack.size() != 0) {
     77                         temp = stack.pop();
     78                         if (temp == '(')
     79                             break;
     80                         else
     81                             suffix += " " + temp;
     82                     }
     83                     // suffix += " ";
     84                     break;
     85                 //如果是数字,直接送至输出序列
     86                 default:
     87                     suffix += c;
     88             }
     89         }
     90 
     91         //如果栈不为空,把剩余的运算符依次弹出,送至输出序列。
     92         while (stack.size() != 0) {
     93             suffix += " " + stack.pop();
     94         }
     95         return suffix;
     96     }
     97 
     98 
     99     /**
    100      * postfix
    101      *
    102      * @return double
    103      */
    104     //方法:通过后缀表达式求出算术结果
    105     public static double suffixToArithmetic(String postfix) {
    106 
    107         Pattern pattern = Pattern.compile("\d+||(\d+\.\d+)"); //使用正则表达式 匹配数字
    108         String strings[] = postfix.split(" ");  //将字符串转化为字符串数组
    109         for (int i = 0; i < strings.length; i++)
    110             strings[i].trim();  //去掉字符串首尾的空格
    111         Stack<Double> stack = new Stack<Double>();
    112 
    113         for (int i = 0; i < strings.length; i++) {
    114 
    115             if (strings[i].equals(""))
    116                 continue;
    117 
    118             //如果是数字,则进栈
    119             if ((pattern.matcher(strings[i])).matches()) {
    120 
    121                 stack.push(Double.parseDouble(strings[i]));
    122             } else {
    123                 //如果是运算符,弹出运算数,计算结果。
    124                 double y = stack.pop();
    125                 double x = stack.pop();
    126                 stack.push(caculate(x, y, strings[i])); //将运算结果重新压入栈。
    127             }
    128         }
    129         return stack.pop(); //弹出栈顶元素就是运算最终结果。
    130 
    131     }
    132 
    133     private static double caculate(double x, double y, String simble) {
    134         if (simble.trim().equals("+"))
    135             return x + y;
    136         if (simble.trim().equals("-"))
    137             return x - y;
    138         if (simble.trim().equals("*"))
    139             return x * y;
    140         if (simble.trim().equals("/"))
    141             return x / y;
    142         return 0;
    143     }
    144 }

    (2)Test.java:(测试类)

     1 public class Test {
     2     public static void main(String[] args) {
     3 
     4         String str = "3+(2-5)*6/3";  //其后缀表达式为325-6*3/+
     5 
     6         //调用方法:中缀表达式转成后缀表达式
     7         System.out.println(StringToArithmetic.infixToSuffix(str));
     8 
     9         //调用方法:给出一个算术表达式(中缀表达式),得到计算结果
    10         System.out.println(StringToArithmetic.stringToArithmetic(str));
    11 
    12     }
    13 
    14 }

    上方代码中,第07行是根据中缀表达式算出后缀表达式。

    第10行:是给出一个中缀表达式,直接的到计算结果,其实它的步骤是:先根据中缀表达式得到后缀表达式,然后根据后缀表达式去计算结果

    运行效果:

    68bb3685-b736-4d3b-95ad-6a6981b80071

  • 相关阅读:
    OD调试4--去除NAG窗口
    《微信小程序项目开发实战:用WePY、mpvue、Taro打造高效的小程序》(笔记3)支持Vue.js语法的mpvue框架
    《微信小程序项目开发实战:用WePY、mpvue、Taro打造高效的小程序》(笔记2)WePY版HelloWorld
    《微信小程序项目开发实战:用WePY、mpvue、Taro打造高效的小程序》(笔记1)WePY开发环境的安装
    《从机器学习到深度学习》笔记(5)集成学习之随机森林
    《从机器学习到深度学习》笔记(4)划分数据集
    《从机器学习到深度学习》笔记(3)强化学习
    《从机器学习到深度学习》笔记(2)无监督学习
    《从机器学习到深度学习》笔记(1)有监督学习
    Koa与Node.js开发实战(3)——Nunjucks模板在Koa中的应用(视频演示)
  • 原文地址:https://www.cnblogs.com/qianguyihao/p/4790373.html
Copyright © 2020-2023  润新知