zoukankan      html  css  js  c++  java
  • [数据结构与算法]栈的应用:计算 2*2+(10-2)/(101-50*2)*3-2+5 表达式的值

      1 import java.util.ArrayList;
      2 import java.util.List;
      3 import java.util.Stack;
      4 import java.util.regex.Matcher;
      5 import java.util.regex.Pattern;
      6 
      7 public class ParseCalcMode {
      8 
      9     public static List parse(String calcMode) {
     10         List elementsList = new ArrayList();
     11         Pattern p = Pattern.compile("(\d+)|([-+*/])|([\(\)])");
     12 
     13         Matcher m = p.matcher(calcMode);
     14         while (m.find()) {
     15             elementsList.add(m.group(0));
     16             //            System.out.println(m.groupCount());
     17         }
     18         return elementsList;
     19     }
     20 
     21     /**
     22      * 进行混合运算
     23      * 
     24      * @param srcStack
     25      * @return
     26      */
     27 
     28     private static String calcMix(Stack srcStack) {
     29         Stack destStack = new Stack();
     30         // 否则有一个完成的带括计算式,则执行计算操作
     31         String data1;
     32         String opr;
     33         String data2;
     34         //
     35         String elem = (String) srcStack.pop();
     36 
     37         // 先执行乘除表式
     38         while (!elem.equals("(")) {
     39             if ("*".equals(elem) || "/".equals(elem)) {
     40 
     41                 data1 = (String) srcStack.pop();
     42                 opr = elem;
     43                 data2 = (String) destStack.pop();
     44 
     45                 Stack tmpStack = new Stack();
     46                 // 如果是连续的乘除,则把连续乘除表达式存入一个临时栈中,待整个连续乘除表达时放完后计算临栈
     47                 while (!srcStack.isEmpty()
     48                         && (srcStack.peek().equals("*") || srcStack.peek().equals("/"))) {
     49                     // 第一次放时
     50                     if (tmpStack.isEmpty()) {
     51                         tmpStack.push(data2);
     52                         tmpStack.push(elem);
     53                         tmpStack.push(data1);
     54                     } else {
     55                         tmpStack.push(srcStack.pop());
     56                         tmpStack.push(srcStack.pop());
     57                     }
     58                     System.out.println("临时栈 tmpStack=" + tmpStack);
     59                 }
     60 
     61                 // 如果不是连续的乘除时
     62                 if (tmpStack.isEmpty()) {
     63 
     64                     switch (opr.charAt(0)) {
     65                     case '*':
     66                         destStack.push(String.valueOf(Integer.parseInt(data1)
     67                                 * Integer.parseInt(data2)));
     68                         break;
     69 
     70                     case '/':
     71                         destStack.push(String.valueOf(Integer.parseInt(data1)
     72                                 / Integer.parseInt(data2)));
     73                         break;
     74                     }
     75 
     76                 } else {
     77 
     78                     destStack.push(calcSameLevel(tmpStack));
     79 
     80                 }
     81 
     82                 System.out.println("乘除计算后 destStack = " + destStack);
     83             } else {
     84                 // 如果不是乘除时直接放入目标栈中
     85                 destStack.push(elem);
     86                 System.out.println("非乘除直接放入 destStack = " + destStack);
     87             }
     88 
     89             if (srcStack.isEmpty()) {
     90                 break;
     91             }
     92             elem = (String) srcStack.pop();
     93         }
     94 
     95         // 如果没有加减时
     96         if (destStack.size() == 1) {
     97             return (String) destStack.pop();
     98         } else {
     99             // 后执行加减表式
    100             return calcSameLevel(destStack);
    101         }
    102 
    103     }
    104 
    105     /**
    106      * 同级运算
    107      * 
    108      * @param destStack
    109      * @return
    110      */
    111     private static String calcSameLevel(Stack destStack) {
    112         String tmpResult = null;
    113         String data1;
    114         String opr;
    115         String data2;
    116 
    117         while (!destStack.isEmpty()) {
    118             if (tmpResult == null) {
    119                 data1 = (String) destStack.pop();
    120 
    121                 opr = (String) destStack.pop();
    122 
    123                 data2 = (String) destStack.pop();
    124 
    125             } else {
    126                 data1 = tmpResult;
    127                 opr = (String) destStack.pop();
    128                 data2 = (String) destStack.pop();
    129             }
    130             switch (opr.charAt(0)) {
    131             case '+':
    132                 tmpResult = String.valueOf(Integer.parseInt(data1)
    133                         + Integer.parseInt(data2));
    134                 break;
    135 
    136             case '-':
    137                 tmpResult = String.valueOf(Integer.parseInt(data1)
    138                         - Integer.parseInt(data2));
    139                 break;
    140             case '*':
    141                 tmpResult = String.valueOf(Integer.parseInt(data1)
    142                         * Integer.parseInt(data2));
    143                 break;
    144 
    145             case '/':
    146                 tmpResult = String.valueOf(Integer.parseInt(data1)
    147                         / Integer.parseInt(data2));
    148                 break;
    149             }
    150         }
    151         System.out.println("同优先级运算结果=" + tmpResult);
    152         return tmpResult;
    153     }
    154 
    155     public static void main(String[] args) {
    156         String str = "2*2+(10-2)/(101-50*2)*3-2+5";
    157         // String str ="2*(3+2-1)";
    158         List elementsList = parse(str);
    159         System.out.println("组成算术表达式的各元素为=" + elementsList);
    160 
    161         // 存入整体算术表达式各元素,在放入过程中如果遇到括号则要先计算括号里的算术式后再把计算出的结果放入栈中
    162         Stack srcStack = new Stack();
    163         for (int i = 0; i < elementsList.size(); i++) {
    164             String elem = (String) elementsList.get(i);
    165             if (elem.equals(")")) {
    166                 System.out.println("遇到右括号,准备计算括号里的算术式,srcStack = " + srcStack);
    167                 srcStack.push(calcMix(srcStack));
    168                 System.out.println("括号里的算术式计算完毕,srcStack = " + srcStack);
    169             } else {
    170                 // 如果不为右括号放入栈
    171                 srcStack.push(elem);
    172                 System.out.println("非右括号,直接入栈 srcStack = " + srcStack);
    173             }
    174         }
    175         System.out.println(srcStack);
    176         // 所有括号里表达式计算完后计算整体算术式
    177         if (srcStack.size() > 1) {
    178             System.out.println("结果为=" + calcMix(srcStack));
    179         } else {
    180             System.out.println("结果为=" + srcStack.pop());
    181         }
    182     }
    183 }

    组成算术表达式的各元素为=[2, *, 2, +, (, 10, -, 2, ), /, (, 101, -, 50, *, 2, ), *, 3, -, 2, +, 5]
    非右括号,直接入栈 srcStack = [2]
    非右括号,直接入栈 srcStack = [2, *]
    非右括号,直接入栈 srcStack = [2, *, 2]
    非右括号,直接入栈 srcStack = [2, *, 2, +]
    非右括号,直接入栈 srcStack = [2, *, 2, +, (]
    非右括号,直接入栈 srcStack = [2, *, 2, +, (, 10]
    非右括号,直接入栈 srcStack = [2, *, 2, +, (, 10, -]
    非右括号,直接入栈 srcStack = [2, *, 2, +, (, 10, -, 2]
    遇到右括号,准备计算括号里的算术式,srcStack = [2, *, 2, +, (, 10, -, 2]
    非乘除直接放入 destStack = [2]
    非乘除直接放入 destStack = [2, -]
    非乘除直接放入 destStack = [2, -, 10]
    同优先级运算结果=8
    括号里的算术式计算完毕,srcStack = [2, *, 2, +, 8]
    非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /]
    非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, (]
    非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, (, 101]
    非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, (, 101, -]
    非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, (, 101, -, 50]
    非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, (, 101, -, 50, *]
    非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, (, 101, -, 50, *, 2]
    遇到右括号,准备计算括号里的算术式,srcStack = [2, *, 2, +, 8, /, (, 101, -, 50, *, 2]
    非乘除直接放入 destStack = [2]
    乘除计算后 destStack = [100]
    非乘除直接放入 destStack = [100, -]
    非乘除直接放入 destStack = [100, -, 101]
    同优先级运算结果=1
    括号里的算术式计算完毕,srcStack = [2, *, 2, +, 8, /, 1]
    非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, 1, *]
    非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, 1, *, 3]
    非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, 1, *, 3, -]
    非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, 1, *, 3, -, 2]
    非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, 1, *, 3, -, 2, +]
    非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, 1, *, 3, -, 2, +, 5]
    [2, *, 2, +, 8, /, 1, *, 3, -, 2, +, 5]
    非乘除直接放入 destStack = [5]
    非乘除直接放入 destStack = [5, +]
    非乘除直接放入 destStack = [5, +, 2]
    非乘除直接放入 destStack = [5, +, 2, -]
    非乘除直接放入 destStack = [5, +, 2, -, 3]
    临时栈 tmpStack=[3, *, 1]
    临时栈 tmpStack=[3, *, 1, /, 8]
    同优先级运算结果=24
    乘除计算后 destStack = [5, +, 2, -, 24]
    非乘除直接放入 destStack = [5, +, 2, -, 24, +]
    非乘除直接放入 destStack = [5, +, 2, -, 24, +, 2]
    乘除计算后 destStack = [5, +, 2, -, 24, +, 4]
    同优先级运算结果=31
    结果为=31

    上面实现的有点复杂了,下面想了下使用 LinkedList 可能要简单一些

    使用LinkedList实现

      1 import java.util.LinkedList;
      2 import java.util.regex.Matcher;
      3 import java.util.regex.Pattern;
      4 
      5 /**
      6  * 使用 LinkedList 计算算术表达试的值
      7  * @author jzj
      8  *
      9  */
     10 public class ArithmeticCalc {
     11     /**
     12      * 提取算术表达式中的括号部分
     13      * 
     14      * @param expression 算术表达式
     15      * @return
     16      */
     17     public static String bracket(String expression) {
     18         Pattern p = Pattern.compile("\(([^\(]+?)\)");
     19 
     20         Matcher m = p.matcher(expression);
     21 
     22         if (m.find()) {
     23             return m.group(1);
     24         }
     25         else {
     26             return null;
     27         }
     28     }
     29 
     30     /**
     31      * 分解算术表达式
     32      * 
     33      * @param expression 算术表达式
     34      * @return
     35      */
     36     public static LinkedList parse(String expression) {
     37         LinkedList elemList = new LinkedList();
     38         //注,减号要放在第一个,放在中间时代表特殊意义
     39         Pattern p = Pattern.compile("(\d+)|[-+*/()]");
     40 
     41         Matcher m = p.matcher(expression);
     42         while (m.find()) {
     43             elemList.add(m.group(0));
     44         }
     45         return elemList;
     46     }
     47 
     48     /**
     49      * 计算不带括号的算术表达式
     50      * @param expression 不带括号的算术表达式
     51      * @return String 返回计算结果
     52      */
     53     private static String caclExpression(String expression) {
     54         //分解算术表达式
     55         LinkedList linkList = parse(expression);
     56 
     57         //先计算乘除
     58         for (int i = 0; i < linkList.size(); i++) {
     59             String e = (String) linkList.get(i);
     60             if ("*".equals(e) || "/".equals(e)) {
     61                 String oprData1 = (String) linkList.remove(i - 1);
     62 
     63                 String opr = (String) linkList.remove(i - 1);
     64 
     65                 String oprData2 = (String) linkList.remove(i - 1);
     66 
     67                 //计算完成后将结果插入到原表达式所在位置
     68                 linkList.add(i - 1, cacl(oprData1, opr, oprData2));
     69 
     70                 i = i - 1 - 1;//从结果位置向后计算
     71             }
     72         }
     73 
     74         //再算计算加减
     75         for (int i = 0; i < linkList.size() && linkList.size() > 1; i++) {
     76             String oprData1 = (String) linkList.remove(i);
     77             String opr = (String) linkList.remove(i);
     78             String oprData2 = (String) linkList.remove(i);
     79             //计算完成后将结果插入到原表达式所在位置
     80 
     81             linkList.add(i, cacl(oprData1, opr, oprData2));
     82             i = i - 1;//从结果位置向后计算
     83         }
     84 
     85         return (String) linkList.get(0);
     86     }
     87 
     88     /**
     89      * 两个数计算
     90      * @param oprData1 操作数一
     91      * @param opr 操作
     92      * @param oprData2 操作数二
     93      * @return String 返回计算结果
     94      */
     95     private static String cacl(String oprData1, String opr, String oprData2) {
     96         switch (opr.charAt(0)) {
     97         case '+':
     98             return String.valueOf(Integer.parseInt(oprData1)
     99                     + Integer.parseInt(oprData2));
    100 
    101         case '-':
    102             return String.valueOf(Integer.parseInt(oprData1)
    103                     - Integer.parseInt(oprData2));
    104         case '*':
    105             return String.valueOf(Integer.parseInt(oprData1)
    106                     * Integer.parseInt(oprData2));
    107 
    108         case '/':
    109             return String.valueOf(Integer.parseInt(oprData1)
    110                     / Integer.parseInt(oprData2));
    111         default:
    112             return "";
    113         }
    114     }
    115 
    116     public static void main(String[] args) {
    117         String expression = "2*2+(2+5/(10-2*(1+1)*2-1))/(7-3*2)*3-2+5";
    118         String bracketStr;
    119         //如果算术表达式中有括号,则先计算括号中的表达式
    120         while ((bracketStr = bracket(expression)) != null) {
    121             String result = caclExpression(bracketStr);
    122             System.out.println(bracketStr + "=" + result);
    123             bracketStr = bracketStr.replaceAll("\*", "\\*").replaceAll(
    124                     "\+", "\\+");
    125             expression = expression.replaceAll("\(" + bracketStr + "\)",
    126                     result);
    127         }
    128 
    129         System.out.println(expression + "=" + caclExpression(expression));
    130     }
    131 }
  • 相关阅读:
    node
    github
    [模块] pdf转图片-pdf2image
    python 15 自定义模块 随机数 时间模块
    python 14 装饰器
    python 13 内置函数II 匿名函数 闭包
    python 12 生成器 列表推导式 内置函数I
    python 11 函数名 迭代器
    python 10 形参角度 名称空间 加载顺序
    python 09 函数参数初识
  • 原文地址:https://www.cnblogs.com/jiangzhengjun/p/4289892.html
Copyright © 2011-2022 走看看