算法与数据结构--栈的应用-逆波兰计算器完整版代码

Posted djames23

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法与数据结构--栈的应用-逆波兰计算器完整版代码相关的知识,希望对你有一定的参考价值。

逆波兰计算器完整版代码

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的基础知识需要补充。

以上是关于算法与数据结构--栈的应用-逆波兰计算器完整版代码的主要内容,如果未能解决你的问题,请参考以下文章

C++栈的应用:逆波兰式的实现

栈的典型实例问题——后缀表达式(逆波兰记号)的计算

(C语言中)逆波兰算法(及计算器)

数据结构----栈与队列之栈的应用四则运算表达式求值

栈的操作实现逆波兰表达式的计算

栈的应用----四则运算,后缀逆波兰表示法(RPN)