zoukankan      html  css  js  c++  java
  • 【算法与数据结构】--栈的应用-逆波兰计算器完整版代码

    逆波兰计算器完整版代码

    1.将中缀表达式转为后缀表达式

    2.正则表达式

    3.递归调用

    ReversePolishMultiCala.java代码如下:
      1 import java.util.ArrayList;
      2 import java.util.Collections;
      3 import java.util.List;
      4 import java.util.Stack;
      5 import java.util.regex.Pattern;
      6 
      7 /*
      8 1.支持+-()* /
      9 2.多位数,支持小数
     10 3.兼容处理,过滤任何空白字符,包括空格、制表符、换页符
     11 说明:逆波兰计算器完整版考虑的因素较多,下面给出完整版代码,使用:中缀表达式转后缀表达式
     12 */
     13 
     14 public class ReversePolishMultiCala{
     15     /**
     16     * 匹配+-* /()运算符
     17      * */
     18     static final String SYMBOL = "\+|-|\*|/|\(|\)";
     19     //https://baijiahao.baidu.com/s?id=1636927461989417537&wfr=spider&for=pc
     20     //被static关键字修饰的不需要创建对象去调用,直接根据类名就可以去访问。
     21     //static可以让对象共享属性.用来修饰成员变量,将其变为类的成员,从而实现所有对象对于该成员的共享;
     22     static final String LEFT = "(";
     23     static final String RIGHT = ")";
     24     static final String ADD = "+";
     25     static final String MINUS = "-";
     26     static final String TIMES = "*";
     27     static final String DIVISION = "/";
     28     //https://www.cnblogs.com/dolphin0520/p/3736238.html
     29     //对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;
     30     //如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
     31 
     32     /**
     33      * 加减 + -
     34      */
     35     static final int LEVEL_01 = 1;
     36     /**
     37      * 乘除 * /
     38      */
     39     static final int LEVEL_02 = 2;
     40     /**
     41      * 括号
     42      */
     43     static final int LEVEL_HIGH = Integer.MAX_VALUE;
     44 
     45     static Stack<String> stack = new Stack<>();
     46     static List<String> data = Collections.synchronizedList(new ArrayList<String>());
     47     //要实现List的线程安全,可以使用 Collections.synchronizedList
     48 
     49     /**
     50      * 去除所有空白符
     51      * @param s
     52      * @return
     53      */
     54     public static String replaceAllBlank(String s){
     55         // 正则表达式 \s+ 匹配任何空白字符,包括空格、制表符、换页符等等,等价于[f
    
    	v]
     56         //replaceFirst 替换首次匹配,replaceAll 替换所有匹配。
     57         return s.replaceAll("\s+", "");
     58     }
     59     /**
     60      * 判断是不是数字 int double long float
     61      * @param s
     62      * @return
     63      */
     64     public static boolean isNumber(String s){
     65         Pattern pattern = Pattern.compile("[-\+]?[.\d]*$");
     66         return pattern.matcher(s).matches();
     67     }
     68     /**
     69      * 判断是不是运算符
     70      * @param s
     71      * @return
     72      */
     73     public static boolean isSymbol(String s){
     74         return s.matches(SYMBOL);
     75     }
     76     /**
     77      * 匹配运算等级
     78      * @param s
     79      * @return
     80      */
     81     public static int calcLevel(String s){
     82         if("+".equals(s)||"-".equals(s)){
     83             return LEVEL_01;
     84         }else if("*".equals(s)||"/".equals(s)){
     85             return LEVEL_02;
     86         }
     87         return LEVEL_HIGH;
     88     }
     89     /**
     90      * 匹配
     91      * @param s
     92      * @throws Exception
     93      */
     94     public static List<String> doMatch(String s) throws Exception {
     95         if (s == null || "".equals(s.trim())) throw new RuntimeException("data is empty");
     96         if (!isNumber(s.charAt(0) + "")) throw new RuntimeException("data illeagle, start not with a number");
     97         s = replaceAllBlank(s);
     98         System.out.println("doMatch s"+s);
     99 
    100         String each;
    101         int start = 0;
    102 
    103         for (int i = 0; i < s.length(); i++) {
    104             if (isSymbol(s.charAt(i) + "")) {
    105                 each = s.charAt(i) + "";
    106                 System.out.println("eachSymbol"+each+i);
    107                 //栈为空,“(”操作符,或者
    108                 //操作符优先级大于栈顶优先级&&操作符优先级不是()的优先级,直接入栈;当遇到(时不能入栈,走else if.
    109                 //注意逻辑运算符的优先级,先计算&&再计算||
    110                 if (stack.isEmpty() || LEFT.equals(each) || calcLevel(each) > calcLevel(stack.peek())
    111                         && calcLevel(each) < LEVEL_HIGH) {
    112                     System.out.println(i+"	"+calcLevel(each)+"	"+LEVEL_HIGH);
    113                     System.out.println("each"+each);
    114                     stack.push(each);
    115                 } else if (!stack.isEmpty() && calcLevel(each) <= calcLevel(stack.peek())) {
    116                     //栈非空,操作符优先级小于等于栈顶优先级时出栈入列,直到栈为空,或者遇到了(,最后操作符入栈
    117                     while (!stack.isEmpty() && calcLevel(each) <= calcLevel(stack.peek())) {
    118                         if (calcLevel(stack.peek()) == LEVEL_HIGH) {
    119                             break;
    120                         }
    121                         data.add(stack.pop());
    122                     }
    123                     stack.push(each);
    124                 } else if (RIGHT.equals(each)) {
    125                     //匹配到")"操作符,依次出栈入列直到空栈或者遇到第一个"("操作符,此时"("出栈
    126                     while (!stack.isEmpty() && LEVEL_HIGH >= calcLevel(stack.peek())) {
    127                         if (LEVEL_HIGH == calcLevel(stack.peek())) {
    128                             stack.pop();
    129                             break;
    130                         }
    131                         data.add(stack.pop());
    132                     }
    133                 }
    134                 start = i;
    135             } else if (i == s.length() - 1 || isSymbol(s.charAt(i + 1) + "")) {
    136                 each = (start == 0 ? s.substring(start, i + 1) : s.substring(start + 1, i + 1));
    137                 System.out.println("eachNum"+each+'	'+i);
    138                 //如果start为0,each就是将s截取(start, i + 1)
    139                 //substring() 方法返回字符串的子字符串。
    140                 if (isNumber(each)) {
    141                     data.add(each);
    142                     continue;
    143                 }
    144                 throw new RuntimeException("data not match number");
    145             }
    146         }
    147         //如果栈里还有元素,此时元素需要依次出栈入列,可以想象栈里剩下栈顶为/,栈底为+,
    148         //应该依次出栈入列,可以直接翻转整个stack添加到队列
    149         Collections.reverse(stack);
    150         data.addAll(new ArrayList<>(stack));
    151 
    152         System.out.println("doMatch"+data);
    153         return data;
    154     }
    155     /**
    156      * 计算结果
    157      * @param list
    158      * @return
    159      */
    160     public static Double doCalc(List<String> list){
    161         Double d = 0d;
    162         if(list == null || list.isEmpty()){
    163             return null;
    164         }
    165         if(list.size() == 1){
    166             //当list中只有一个元素时即是最终结果
    167             System.out.println(list);
    168             d = Double.valueOf(list.get(0));
    169             //System.out.println(d);
    170             return d;
    171         }
    172         ArrayList<String> list1 = new ArrayList<>();
    173         for(int i = 0;i<list.size();i++){
    174             list1.add(list.get(i));//获取后缀表达式列表的每一个元素并添加到新列表list1中
    175             System.out.println("doCalc"+list1+i);
    176             if(isSymbol(list.get(i))){
    177                 Double d1 = doTheMath(list.get(i-2),list.get(i-1),list.get(i));
    178                 list1.remove(i);//在新列表中删除第i个字符
    179                 list1.remove(i-1);//在新列表中删除第i-1个数字
    180                 list1.set(i-2,d1+"");//在新列表中用d1代替第i-2个数字
    181                 list1.addAll(list.subList(i+1,list.size()));//将原始列表剩下的数字和运算符添加到新列表中
    182                 break;
    183             }
    184         }
    185         doCalc(list1);//递归调用此方法
    186         return d;
    187     }
    188     /**
    189      *运算
    190      * @param s1
    191      * @param s2
    192      * @param symbol
    193      * @return
    194      */
    195     public static Double doTheMath(String s1, String s2, String symbol){
    196         Double result;
    197         switch (symbol){
    198             case ADD:
    199                 result = Double.valueOf(s1) + Double.valueOf(s2);
    200                 break;
    201             case MINUS:
    202                 result = Double.valueOf(s1) - Double.valueOf(s2);
    203                 break;
    204             case TIMES:
    205                 result = Double.valueOf(s1) * Double.valueOf(s2);
    206                 break;
    207             case DIVISION:
    208                 result = Double.valueOf(s1) / Double.valueOf(s2);
    209                 break;
    210             default:
    211                 result = null;
    212         }
    213         return result;
    214     }
    215 
    216     public static void main(String[] args){
    217         //String math = "9+(3-1)*3+10/2";
    218         String math = "12.8 + (2 - 3.55)*4+10/5.0";//8.6
    219         try{
    220             doCalc(doMatch(math));
    221         }catch(Exception e){
    222             e.printStackTrace();
    223         }
    224     }
    225 
    226 }

    运行结果:

    1 [12.8, 2, 3.55, -, 4, *, +, 10, 5.0, /, +]
    2 [8.600000000000001]

    有关递归和正则表达式的内容后面继续学习,另外还有一些java的基础知识需要补充。

  • 相关阅读:
    HTML导航条的制作
    图片样式加hover特效
    用表格制作商品购买页面--(table)
    CSS-盒子模型
    一些常见css样式加选择器
    css的一些样式
    HTML基本代码
    element-ui的tab切换同步步骤条 字符串转数字 数字转字符串
    vuex相关知识笔记
    js: 数组方法(中级)
  • 原文地址:https://www.cnblogs.com/DJames23/p/13126458.html
Copyright © 2011-2022 走看看