后缀表达式求值(逆波兰表达式)--java版本

这篇博客介绍了如何在Java中处理后缀表达式求值和中缀表达式转后缀表达式的过程。通过设置栈进行计算,详细解释了每个步骤,并提供了具体的操作数和运算符的处理示例。最后提到了中缀表达式转换的代码实现思路。

该篇中表达式运算(加减乘除 取余 幂运算),包括小数,带有各种英文括号,以及多余符号的去除,有关的原理也可以参照上一篇文章.

中缀表达式求值

一.后缀表达式

(1) 简介:

  又称逆波兰式,指的是不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则),使用中缀表达式符合人的思维习惯,但是后缀表达式便于计算机.
  因此,我们将中缀表达式转换为后缀表达式在作计算.

(2) 后缀表达式求值

思路:
 设置一个栈.遍历表达式.

  1. 如果遇到操作数,压入栈中
  2. 如果遇到运算符,从栈顶弹出两个操作符并且做运算,运算结果压入栈中.
  3. 栈中最后留下的数就是最终的结果.

举例: 4 5 * 8 - 60 + 8 2 / +

  1. 操作数压入栈中,因此,4 和 5压入栈中
  2. 遇到运算符*号,从栈中弹出两个操作数,进行运算,结果压入栈中,弹出4和5,结果20压栈.
  3. 遇到8压栈
  4. 遇到 - 号,计算,得到结果 12 压入栈中
  5. 遇到60 压入栈中
  6. 遇到 + 号,计算得到结果72
  7. 8 和 2压入栈中
  8. / ,弹出8 和 2,计算得到4,压入栈中
  9. +, 弹出72 和 4 ,计算,得到76
  10. 最终结果为76
(3) 后缀表达式求值代码实现
  private static float calculate(List<String> s) {
       Stack<String> stack = new Stack<>();
       for (String it : s) {
       // 如果为操作数,直接入栈
           if (it.matches("[1-9]\\d*\\.?\\d*")) {
               stack.push(it);
           } else {
           // 如果为运算符,则从栈顶弹出两个操作数,并进行运算,将结果压入栈中
               float num1 = Float.parseFloat(stack.pop());
               float num2 = Float.parseFloat(stack.pop());
               float res = 0;
               switch (it) {
                   case "+": {
                       res = num1 + num2;
                       break;
                   }
                   case "-": {
                       res = num2 - num1;
                       break;
                   }
                   case "*": {
                       res = num2 * num1;
                       break;
                   }
                   case "/": {
                       res = num2 / num1;
                       break;
                   }
                   case "%": {
                       res = num2 % num1;
                       break;
                   }
                   case "^": {
                       res = 1;
                       for (int i = 1; i <= num1; i++) {
                           res *= num2;
                       }
                       break;
                   }
                   default: {
                       System.out.println("该符号不正确");
                       res = -999999;
                       break;
                   }
               }
               stack.push(res + "");
           }
       }
       return Float.parseFloat(stack.pop());
   }

二.中缀表达式转后缀表达式

(1) 思路:
  1. 初始化一个栈operS,该栈用来存储符号;初始化一个集合res,用来存储中间结果.

  2. 从左至右扫描中缀表达式

  3. 如果遇到操作数时,直接加入到res中.

  4. 如果遇到括号时
    A. 为左括号,直接压入栈operS中
    B. 为右括号,依次弹出operS栈顶的运算符加入到res中,知道遇到左括号,此时,将这一对括号舍弃.

  5. 如果遇到运算符,比较其与operS栈顶运算符的优先级.
    A. 如果栈空,或者栈顶为左括号,或者当前运算符优先级 > 栈顶运算符优先级,则将该运算符压入栈中.
    B. 否则,如果当前运算符优先级 <= 栈顶运算符优先级,则弹出栈顶运算符加入到res中,再次与新的栈顶运算符优先级作比较.

  6. 重复以上步骤,直到表达式扫描结束.

  7. 将operS栈中剩余运算符依次弹出并加入到res集合中

  8. res中保存着的就是转换后的后缀表达式.

(2) 举例: 4*5-(8+6)*2+8/2

在这里插入图片描述
在这里插入图片描述 在这里插入图片描述 在这里插入图片描述
在这里插入图片描述 在这里插入图片描述
最后的结果就是45 * 8 6 + 2 * - 8 2 /

(3) 代码实现

调用

 public static float houCaculate(String str){
//        将中缀表达式转换为集合
        List<String> list = toHouList(str);
//        将中缀表达式集合转换为后缀表达式
        List<String> list1 = toHou(list);
//        计算后缀表达式
        return calculate(list1);

    }

将中缀表达式转换为后缀表达式


   /**
     * 将中缀表达式转换为后缀表达式
     *
     * @param list
     * @return
     */
    private static List<String> toHou(List<String> list) {
//        设置一个符号栈
        Stack<String> operS = new Stack<>();
//        设置List集合装结果
        List<String> res = new ArrayList<>();

        for (String it : list) {
//            如果当前指向为操作数,直接入集合
            if (it.matches("[1-9]\\d*\\.?\\d*")) {
                res.add(it);
            } else if (isLeft(it) || operS.isEmpty() || isLeft(operS.peek())) {
//                如果当前指向为左括号,或者栈是空的,或者栈顶是左括号,直接入符号栈
                operS.push(it);
            } else if (isRight(it)) {
//                符号栈一直出栈,直到遇到左括号.出栈的符号加入到集合中
                while (!isLeft(operS.peek())) {
                    res.add(operS.pop());
                }

//             将右括号舍弃
                if (priority(it) == priority(operS.peek()))
                    operS.pop();
                else {
                    System.out.println("括号匹配有问题");
                    return null;
                }
            } else if (priority(operS.peek()) < priority(it)) {
//                当前运算符优先级大于栈顶优先级
                operS.push(it);
            } else {

                while (!operS.isEmpty() && priority(operS.peek()) >= priority(it)) {
                    res.add(operS.pop());
                }
                operS.push(it);
            }
        }

        while (!operS.isEmpty()) {
            res.add(operS.pop());
        }
        return res;
    }
 // 判断是否是一个数字
    private static boolean isNumber(char c) {
        if (c >= '0' && c <= '9')
            return true;
        return false;
    }
//    过滤一些特殊符号
    private static String filtration(String str){
        String regEx = "[`~!@#$&|:<>?~!@#¥%……&()——|【】‘;:”“’。,、?\t\n]";
        return Pattern.compile(regEx).matcher(str).replaceAll("").replace(" ","");
    }

将中缀表达式转换成List

 /**
     * 将中缀表达式转换成List
     *
     * @param str
     * @return
     */
    private static List<String> toHouList(String str) {
//        设置一个index索引遍历s
        int index = 0;
        String s = filtration(str);
//        设置List装结果
        List<String> list = new ArrayList<>();
        do {
            //            如果当前指向是符号
            if (!isNumber(s.charAt(index))) {
                list.add(s.charAt(index) + "");
                index++;
            }

//            如果当前指向为数字
            else {
                String num = "";
                while (isNumber(s.charAt(index)) || s.charAt(index) == '.') {
                    num += s.charAt(index);
                    index++;
                    if(index == s.length()) break;
                }
      // 避免num中出现多个小数点,或者第一位为小数点
                if (num != "" && num.charAt(0) != '.' && num.split("\\.").length <= 2)
                    list.add(num);
            }

        } while (index <= s.length() - 1);

        return list;
    }

返回运算符的优先级

/**
     * 返回运算符的优先级
     *
     * @param oper
     * @return
     **/
    //    返回元素的优先级
    private static int priority(String oper) {
        int val = 100;
        switch (oper) {
            case "*":
            case "%":
            case "/": {
                val = 1;
                break;
            }
            case "^": {
                val = 2;
                break;
            }
            case "+":
            case "-": {
                val = 0;
                break;
            }
            case "[":
            case "]": {
                val = -1;
                break;
            }
            case "{":
            case "}": {
                val = -2;
                break;
            }
            case "(":
            case ")": {
                val = -3;
                break;
            }

        }
        return val;
    }

判断左括号或者右括号

  // 判断是否为左括号
    private static boolean isLeft(String v) {
        if (v.equals("(") || v.equals("[") || v.equals("{")) return true;
        return false;
    }


    //    判断是否为右括号
    private static boolean isRight(String v) {
        if (v.equals(")") || v.equals("]") || v.equals("}")) return true;
        return false;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值