算法与数据结构--栈的应用-逆波兰计算器完整版代码
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的基础知识需要补充。
以上是关于算法与数据结构--栈的应用-逆波兰计算器完整版代码的主要内容,如果未能解决你的问题,请参考以下文章