有两个实体类:一个是逆波兰表达式类,一个是真分数类,还有一个工具类,生成随机数和栈深度复制
生成四则运算式通过先生成逆波兰表达式再转换为中序表达式来完成,计算通过直接计算逆波兰表达式的值,这就产生了三个功能需要实现:生成逆波兰表达式、转为中序表达式、计算。
真分数实现了生成,化简,加减乘除功能,可以加入四则运算式运算。
支持可变运算式长度
这里只粘逆波兰表达式代码吧
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 package cn.edu.tju.showmethecode.calculate; 2 3 import java.util.Stack; 4 5 import sun.rmi.runtime.Log; 6 7 8 public class RPNExpression { 9 10 private Stack<Object> RPNExp = new Stack<Object>(); //逆波兰表达式 11 private int length; //运算数个数 12 private String value; //表达式的值 13 14 public RPNExpression() { 15 this(4); 16 } 17 18 public RPNExpression(int length) { 19 if(length<2) 20 throw new IllegalArgumentException("长度设置过短!"); 21 22 this.length = length; 23 generateRPNExp(length); 24 calcValue(); 25 } 26 27 private void generateRPNExp(int length) { 28 int symbolCount = 0; 29 int operatorCount = 0; 30 while(operatorCount + symbolCount < length * 2 - 1){ 31 32 if(operatorCount-1 > symbolCount && operatorCount < length){ 33 if(Utils.getRandomBoolean()){ //true生成运算符,false操作数 34 this.RPNExp.push(generateSymbol()); 35 symbolCount ++; 36 }else{ 37 this.RPNExp.push(Utils.getRandomBoolean() ? generateNumeric() : generateProperFraction()); 38 operatorCount ++; 39 } 40 }else if(operatorCount-1 <= symbolCount && operatorCount < length) { //true生成整数,false生成分数 41 this.RPNExp.push(Utils.getRandomBoolean() ? generateNumeric() : generateProperFraction()); 42 operatorCount ++; 43 }else if(operatorCount-1 > symbolCount && operatorCount >=length) { 44 this.RPNExp.push(generateSymbol()); 45 symbolCount ++; 46 } 47 } 48 } 49 50 private int generateNumeric() { 51 return Utils.getRandomInteger(1, 100); 52 } 53 54 private char generateSymbol() { 55 char[] symbol = {'+','−','×','÷'}; 56 return symbol[Utils.getRandomInteger(0, 4)]; 57 } 58 59 private ProperFraction generateProperFraction() { 60 int denominator = Utils.getRandomInteger(2, 10); 61 int numerator = Utils.getRandomInteger(1, denominator); 62 return new ProperFraction(numerator, denominator); 63 } 64 /* 65 * get逆波兰表达式 66 */ 67 public static String generateArithmetic(int length){ 68 return (new RPNExpression(length)).convertToSeqExp(); 69 } 70 71 private void calcValue(){ 72 Stack<Object> RPNStack = Utils.cloneStack(this.RPNExp); 73 Stack<Object> numStack = new Stack<Object>(); //数字栈 74 75 while(!RPNStack.empty()){ 76 if(RPNStack.peek() instanceof Integer || RPNStack.peek() instanceof ProperFraction){ 77 numStack.push(RPNStack.pop()); 78 }else if(RPNStack.peek() instanceof Character){ 79 Object rightOperator = numStack.pop(); 80 Object leftOperator = numStack.pop(); 81 if(rightOperator instanceof Integer) 82 rightOperator = new ProperFraction((Integer) rightOperator, 1); 83 if(leftOperator instanceof Integer) 84 leftOperator = new ProperFraction((Integer) leftOperator, 1); 85 86 switch ((Character) RPNStack.pop()) { 87 case '+': 88 numStack.push(((ProperFraction)leftOperator).add((ProperFraction)rightOperator)); 89 break; 90 case '−': 91 numStack.push(((ProperFraction)leftOperator).minus((ProperFraction)rightOperator)); 92 break; 93 case '×': 94 numStack.push(((ProperFraction)leftOperator).multiply((ProperFraction)rightOperator)); 95 break; 96 case '÷': 97 numStack.push(((ProperFraction)leftOperator).devide((ProperFraction)rightOperator)); 98 break; 99 default: 100 // throw new Exception(""); 101 break; 102 } 103 } 104 } 105 106 this.value = ((ProperFraction) numStack.pop()).toString(); 107 } 108 109 private String convertToSeqExp() { 110 System.out.println(this.RPNExp.toString()); 111 Stack<Object> RPNStack = Utils.cloneStack(this.RPNExp); 112 Stack<String> tempExpStack = new Stack<String>(); //临时表达式栈 113 114 while(!RPNStack.empty()){ 115 if(RPNStack.peek() instanceof Integer || RPNStack.peek() instanceof ProperFraction){ 116 tempExpStack.push(RPNStack.pop().toString()); 117 }else if(RPNStack.peek() instanceof Character){ 118 String rightOperator = tempExpStack.pop(); 119 String leftOperator = tempExpStack.pop(); 120 121 if("×÷−".contains(RPNStack.peek().toString())){ 122 if(isNeedBrackets((Character) RPNStack.peek(), rightOperator, true)){ 123 rightOperator = "( " + rightOperator + " )"; 124 } 125 if(isNeedBrackets((Character) RPNStack.peek(), leftOperator, false)){ 126 leftOperator = "( " + leftOperator + " )"; 127 } 128 } 129 130 tempExpStack.push(leftOperator + " " + RPNStack.pop().toString() + " " + rightOperator); 131 } 132 } 133 134 return tempExpStack.pop(); 135 } 136 137 /* 138 * 判断一个临时表达式是否需要加括号, 139 * 有三种情况: 140 * 1. 当前符号是 ×÷,临时表达式符号是 +− 141 * 2. 当前符号是 −,临时表达式是右操作数,且符号为 +− 142 * 3. 当前符号是 ÷,临时表达式是右操作数,且符号为 ×÷ 143 */ 144 private boolean isNeedBrackets(Character currentSymbol, String tempExp, boolean rightOrNot) { 145 //判断括号外是什么符号 146 String priority = symbolOutsideOfBranckets(tempExp); 147 148 if("+−".equals(priority) && "×÷".contains(currentSymbol.toString())) { 149 return true; 150 } 151 if("×÷".equals(priority) && rightOrNot && "÷".equals(currentSymbol.toString())) { 152 return true; 153 } 154 if("+−".equals(priority) && rightOrNot && "−".equals(currentSymbol.toString())) { 155 return true; 156 } 157 158 return false; 159 } 160 161 /* 162 * 判断临时操作数最外层的符号是什么,×÷ 或 +− 后者无符号 163 * count是括号的左括号的数量 164 */ 165 private String symbolOutsideOfBranckets(String tempExp) { 166 if(!tempExp.contains(" ")){ 167 return "nothing"; 168 } 169 170 String[] elements = tempExp.split(" "); 171 int count = 0; 172 173 for(int i=0; i<elements.length; i++){ 174 if(count == 0 && "+−".contains(elements[i])) { 175 return "+−"; 176 }else if("(".equals(elements[i])) { 177 count ++; 178 }else if(")".equals(elements[i])) { 179 count --; 180 } 181 } 182 return "×÷"; 183 } 184 185 public int getLength() { 186 return this.length; 187 } 188 189 public String getSeqExp() { 190 return convertToSeqExp(); 191 } 192 193 public String getValue() { 194 return this.value; 195 } 196 197 public String toString() { 198 Stack<Object> RPNStack = Utils.cloneStack(this.RPNExp); 199 StringBuilder sb = new StringBuilder(); 200 while(!RPNStack.empty()) 201 sb.append(RPNStack.pop().toString()).append(" "); 202 return sb.toString(); 203 } 204 }
于阜甲