java数据结构和算法——完整版的逆波兰计算器的应用示例

一、完整版的逆波兰计算器的支持

  • 支持+ - * / ( )
  • 支持多位数及小数
  • 兼容处理,过滤任何空白字符,包括空格、制表符、换页符

二、完整版的逆波兰计算器代码示例

1、代码如下:

package com.rf.springboot01.dataStructure.stack.reversePolishNotation;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
import java.util.regex.Pattern;

/**
 * @description: 完整版的逆波兰计算器
 *                 1、支持+ - * / ( )
 *                 2、支持多位数及小数,
 *                 3、兼容处理,过滤任何空白字符,包括空格、制表符、换页符
 * @author: xiaozhi
 * @create: 2020-07-29 22:28
 */
public class ReversePolishMultiCalc {

    //匹配 + - * /运算符
    public static final String SYMBOL="\\+|-|\\*|/|\\(|\\)";
    public static final String LEFT="(";
    public static final String RIGHT=")";
    public static final String ADD="+";
    public static final String SUB="-";
    public static final String MUL="*";
    public static final String DIV="/";

    //运算符等级
    public static final int LEVEL_1=1;// + - 符号等级
    public static final int LEVEL_2=2;// * / 符号等级
    public static final int LEVEL_HIGHT=Integer.MAX_VALUE;//括号() 符号的等级

    //定义栈
    static Stack<String> stack =new Stack<>();
    static List<String> data= Collections.synchronizedList(new ArrayList<>());

    //去除所有空白符
    public static String replaceAllBlank(String str){
        // \\s+匹配任何空白字符,包括空格、制表符、换页符等等,等价于[\f\n\r\t\v]
        return str.replaceAll("\\s+","");
    }

    // 是否是数字 int  long float double
    public static boolean isNumber(String str){
        //提取字符串中自定的字符
        Pattern pattern = Pattern.compile("^[-\\+]?[.\\d]*$");
        return pattern.matcher(str).matches();
    }

    //判断是不是运算符
    public static boolean isSymbol(String str){
        return str.matches(SYMBOL);
    }

    //匹配运算等级
    public static int calcLevel(String str){
        if("+".equals(str) || "-".equals(str)){
            return LEVEL_1;
        }else if("*".equals(str)|| "/".equals(str)){
            return LEVEL_2;
        }
        return LEVEL_HIGHT;

    }
    
    //匹配
    public static List<String> doMatch (String s) throws Exception{
        if(s == null || "".equals(s.trim())) throw new RuntimeException("data is empty");
        if(!isNumber(s.charAt(0)+"")) throw new RuntimeException("data illeagle,start not with a number");

        s = replaceAllBlank(s);

        String each;
        int start = 0;

        for (int i = 0; i < s.length(); i++) {
            if(isSymbol(s.charAt(i)+"")){
                each = s.charAt(i)+"";
                //栈为空,(操作符,或者 操作符优先级大于栈顶优先级 && 操作符优先级不是( )的优先级 及是 ) 不能直接入栈
                if(stack.isEmpty() || LEFT.equals(each)
                        || ((calcLevel(each) > calcLevel(stack.peek())) && calcLevel(each) < LEVEL_HIGHT)){
                    stack.push(each);
                }else if( !stack.isEmpty() && calcLevel(each) <= calcLevel(stack.peek())){
                    //栈非空,操作符优先级小于等于栈顶优先级时出栈入列,直到栈为空,或者遇到了(,最后操作符入栈
                    while (!stack.isEmpty() && calcLevel(each) <= calcLevel(stack.peek()) ){
                        if(calcLevel(stack.peek()) == LEVEL_HIGHT){
                            break;
                        }
                        data.add(stack.pop());
                    }
                    stack.push(each);
                }else if(RIGHT.equals(each)){
                    // ) 操作符,依次出栈入列直到空栈或者遇到了第一个)操作符,此时)出栈
                    while (!stack.isEmpty() && LEVEL_HIGHT >= calcLevel(stack.peek())){
                        if(LEVEL_HIGHT == calcLevel(stack.peek())){
                            stack.pop();
                            break;
                        }
                        data.add(stack.pop());
                    }
                }
                start = i ;    //前一个运算符的位置
            }else if( i == s.length()-1 || isSymbol(s.charAt(i+1)+"") ){
                each = start == 0 ? s.substring(start,i+1) : s.substring(start+1,i+1);
                if(isNumber(each)) {
                    data.add(each);
                    continue;
                }
                throw new RuntimeException("data not match number");
            }
        }
        //如果栈里还有元素,此时元素需要依次出栈入列,可以想象栈里剩下栈顶为/,栈底为+,应该依次出栈入列,可以直接翻转整个stack 添加到队列
        Collections.reverse(stack);
        data.addAll(new ArrayList<>(stack));

        System.out.println(data);
        return data;
    }

    //计算结果
    public static Double doCalc(List<String>list){
        Double d=0d;
        if(list==null||list.isEmpty()){
            return null;
        }
        if(list.size()==1){
            System.out.println(list);
            d =Double.valueOf(list.get(0));
            return d;
        }
        ArrayList<String>list1=new ArrayList<>();
        for(int i=0;i<list.size();i++){
            list1.add(list.get(i));
            if(isSymbol(list.get(i))){
                Double d1=doTheMath(list.get(i-2),list.get(i-1),list.get(i));
                list1.remove(i);
                list1.remove(i-1);
                list1.set(i-2,d1+"");
                list1.addAll(list.subList(i+1,list.size()));
                break;
            }
        }
        doCalc(list1);
        return d;
    }
    
    //运算
    public static Double doTheMath(String s1,String s2,String symbol){
        Double result;
        switch(symbol){
            case ADD:
                result=Double.valueOf(s1)+Double.valueOf(s2);
                break;
            case SUB:
                result=Double.valueOf(s1)-Double.valueOf(s2);
                break;
            case MUL:
                result=Double.valueOf(s1)*Double.valueOf(s2);
                break;
            case DIV:
                result=Double.valueOf(s1)/Double.valueOf(s2);
                break;
            default:
                result=null;
        }
        return result;
    }

    public static void main(String[] args) {
        String math="12.8+(2-3.55)*4+10/5.0";
        //String math="9+(3-1)*3+10/2";
        try{
            doCalc(doMatch(math));
        }catch(Exception e){
            e.printStackTrace();
        }
    }

}

2、运行测试类,结果如下:
java数据结构和算法——完整版的逆波兰计算器的应用示例_第1张图片

你可能感兴趣的:(java数据结构和算法)