题目:
设计思想:
生成运算式:用随机数产生2-10之间的数当做运算式的长度,再随机产生相应个数的随机数当做运算数,随机产生0-1或0-3当做运算符。
因为要产生的随机数分为整数和分数,所以讲产生随机数的功能封装为一个函数,代码如下:
1 //随机生成一个运算数( type==0代表生成整数,type==1代表生成真分数,maxNum代表数值范围 0-(maxNum-1) ) 2 public static String getOperatorNumber(int type,int maxNum){ 3 Random rd = new Random(); 4 int a; 5 while(true){ 6 a = rd.nextInt(maxNum); 7 if(type == 0){//随机生成一个整数 8 return "" + a; 9 }else{//随机生成一个真分数 10 if(a == 0){ 11 continue; 12 } 13 int b = rd.nextInt(a); 14 FenShu c = new FenShu(a,b); 15 return c.toString(); 16 } 17 } 18 } 19
随机产生括号:
假设运算式的运算数个数为n,则定义一个长度为n的整型数组 a,第i个元素对应第i个运算数,最后根据第i个数组元素的值来判断第i个运算数周围有什么括
(0代表没有括号,+s代表有s个左括号,-s代表有s个右括号)
则可以产生的括号的长度(即括号包围的运算数的个数)为2 ~ (n-1),
利用for循环控制括号的长度,循环变量 i 为2 ~ (n - 1)
循环体是另一个循环,循环变量 j 为0 ~ (n - i + 1) (即可以加左括号的运算数的位置)
内层循环循环体为:随机生成0或1,1代表加括号,但是还要判断在这是否可以加括号,如果a[j] >=0 (即这个运算数这没有右括号) 且 a[j + i - 1] <= 0
(即产生的这个括号的右括号的那个运算数周围没有左括号) 且 sum(a[j] ...... a[j + i - 1]) == 0 (即要加的这个括号之间的括号必须全部匹配,不能因为加上这个括号产生括号交叉现象)
代码为:
1 //随机生成括号,参数为运算式的运算数的个数 2 public static int[] randomAddBracket(int length){ 3 int[] brackets = new int[length]; 4 for(int i = 0;i < brackets.length;i++) brackets[i] = 0; 5 Random rd = new Random(); 6 for(int i = 2;i < length;i++){//添加的括号长度(括号包围的运算数的个数) 7 for(int j = 0;j < length - i + 1;j++){ 8 int t = rd.nextInt(2);//随机生成0或1,0代表不加括号,1代表加括号 9 if(t == 1){ 10 if(brackets[j] >= 0 && brackets[j + i - 1] <= 0){//要加的括号的第一个运算数周围没有右括号,且 最后一个运算数周围没有左括号 11 int counteract = 0; 12 for(int k = j;k < j + i;k++){//将要加的括号之间的所有运算数对应的brackets相加, 13 //如果和为0说明这个括号之间的括号是匹配的,不会出现括号交叉现象 14 counteract += brackets[k]; 15 } 16 if(counteract == 0){ 17 brackets[j]++; 18 brackets[j + i - 1]--; 19 } 20 } 21 } 22 } 23 } 24 return brackets; 25 } 26
上面方法有bug,修改版为:
// 随机生成括号,参数为运算式的运算数的个数 private static int[] randomAddBracket(int length) throws MyException { if(length <= 1) { throw new MyException("运算式长度不能小于2"); } int[] brackets = new int[length]; for (int i = 0; i < brackets.length; i++) brackets[i] = 0; Random rd = new Random(); for (int i = 2; i < length; i++) {// 添加的括号长度(括号包围的运算数的个数) for (int j = 0; j < length - i + 1; j++) { int t = rd.nextInt(2);// 随机生成0或1,0代表不加括号,1代表加括号 if (t == 1) { if (brackets[j] >= 0 && brackets[j + i - 1] <= 0) {// 要加的括号的第一个运算数周围没有右括号,且 // 最后一个运算数周围没有左括号 int counteract1 = 0,counteract2 = 0,counteract3 = 0; for (int k = j; k < j + i; k++) {// 将要加的括号之间的所有运算数对应的brackets相加, // 如果和为0说明这个括号之间的括号是匹配的,不会出现括号交叉现象 counteract1 += brackets[k]; } for (int k = 0; k < j - 1; k++) {// 将要加的括号之前的所有运算数对应的brackets相加, // 如果和为0说明这个括号之间的括号是匹配的,不会出现括号交叉现象 counteract2 += brackets[k]; } for (int k = j + i; k < length; k++) {// 将要加的括号之后的所有运算数对应的brackets相加, // 如果和为0说明这个括号之间的括号是匹配的,不会出现括号交叉现象 counteract3 += brackets[k]; } if (counteract1 == 0 && counteract2 == 0 && counteract3 == 0) { brackets[j]++; brackets[j + i - 1]--; j += i; } } } } } return brackets; }
表达式计算:利用堆栈将中缀表达式转换为后缀表达式进行运算
代码为:
1 //表达式计算,参数为字符串类型的运算式 2 public static String expressCalculate(String express,int hasFuShu,int hasYuShu,int type,int symbolNum){ 3 Stack<String> num = new Stack<String>(); 4 Stack<String> symbolS = new Stack<String>(); 5 symbolS.push("#"); 6 express += "#"; 7 char ch; 8 int i = 0; 9 int s = 0; 10 ch = express.charAt(i); 11 while(s < symbolNum){ 12 if(ch == ' '){//读到空格,说明开始读运算数 13 String readNumStr = ""; 14 while(true){ 15 ch = express.charAt(++i); 16 if(ch == ' '){ 17 break; 18 } 19 readNumStr += ch; 20 21 } 22 if((i + 1) < express.length()){ 23 ch = express.charAt(++i); 24 } 25 num.push(readNumStr); 26 }else{//读到的是运算符 27 char compare = priorityCompare(symbolS.peek(),ch + ""); 28 29 if(compare == '='){//如果是右括号 30 symbolS.pop(); 31 ch = express.charAt(++i); 32 }else if(compare == '>'){//ch的优先级小于栈顶的优先级 比栈顶的优先级高就不算,入栈,低就弹栈运算 33 //弹出两个运算数,弹出一个运算符 34 String bStr = num.pop(); 35 String aStr = num.pop(); 36 String symbolT = symbolS.pop(); 37 String c = yunSuan(aStr,bStr,symbolT,hasFuShu,hasYuShu,type); 38 if(c.equals("ERROR")){ 39 return "ERROR"; 40 }else if(c.indexOf("余") >= 0 && s != symbolNum - 1){//有余数 41 return "ERROR"; 42 }else{ 43 num.push(c); 44 } 45 s++; 46 }else{ 47 symbolS.push(ch + ""); 48 if((i + 1) < express.length()){ 49 ch = express.charAt(++i); 50 } 51 } 52 53 } 54 } 55 return num.pop(); 56 }
程序全部代码为
1 package test; 2 3 /* 4 * 是否有乘除法 5 * 括号 6 * 数值范围 7 * 加减有无负数 8 * 除法余数 9 */ 10 11 import java.util.Random; 12 import java.util.Scanner; 13 import java.util.Stack; 14 15 16 17 public class SiZe { 18 19 public static void main(String[] args) { 20 // TODO Auto-generated method stub 21 Scanner scan = new Scanner(System.in); 22 System.out.println("0、整数式 1、分数式"); 23 int type = scan.nextInt(); 24 System.out.println("生成的运算式个数:"); 25 int n = scan.nextInt(); 26 System.out.println("是否有乘除法(1有,0没有)"); 27 int hasChengChu = scan.nextInt(); 28 System.out.println("是否有括号(1有,0没有)"); 29 int hasKuoHao = scan.nextInt(); 30 System.out.println("加减有无负数(1有,0没有)"); 31 int hasFuShu = scan.nextInt(); 32 System.out.println("除法有无余数(1有,0没有)"); 33 int hasYuShu = scan.nextInt(); 34 System.out.println("数值范围(最大数)"); 35 int maxNum = scan.nextInt(); 36 String[] yunSuanShiArray = createYunSuanShi(hasChengChu, hasKuoHao, hasFuShu, hasYuShu, maxNum, n, type); 37 for(int i = 0;i < yunSuanShiArray.length;i++){ 38 System.out.println(yunSuanShiArray[i]); 39 } 40 scan.close(); 41 } 42 43 44 //生成整数计算式添加限制条件,type为运算式类型 0代表整数式,1代表真分数式 45 public static String[] createYunSuanShi(int hasChengChu,int hasKuoHao,int hasFuShu,int hasYuShu,int maxNum,int n,int type) { 46 int i = 0; 47 String yunSuanShiTemp; 48 String[] yunSuanShiArray = new String[n]; 49 int operatorScope = 2 + 2 * hasChengChu;//运算符范围,2或4,2代表只有加减,4代表有加减乘除 50 int length; 51 String[] operatorArray = {"+","-","*","/"}; 52 String[] operatorNum = null;//存储运算数 53 int num_index;//运算数下标 54 String[] operatorSymbol = null;//存储运算符 55 int symbol_index;//运算符下标 56 int[] brackets = null;//存储括号个数 57 58 while(i < n) { 59 length = Integer.parseInt(getOperatorNumber(0, 9)) + 2;//计算式运算数长度 60 operatorNum = new String[length]; 61 operatorSymbol = new String[length - 1]; 62 num_index = 0; 63 symbol_index = 0; 64 operatorNum[num_index++] = getOperatorNumber(type, maxNum);//随机生成操作数 65 for(int j = 0;j < length - 1;j++){ 66 operatorSymbol[symbol_index++] = operatorArray[Integer.parseInt(getOperatorNumber(0, operatorScope))];//随机生成操作符 67 operatorNum[num_index++] = getOperatorNumber(type, maxNum);//随机生成操作数 68 } 69 if(hasKuoHao == 1){ 70 brackets = randomAddBracket(length);//生成括号数组 71 } 72 //构造运算式 73 yunSuanShiTemp = ""; 74 for(int j = 0;j < length;j++){ 75 //添加左括号 76 if(hasKuoHao == 1){ 77 for(int k = 0;k < brackets[j];k++){ 78 yunSuanShiTemp += "("; 79 } 80 } 81 yunSuanShiTemp += " " + operatorNum[j] + " ";//加上运算数 82 83 //添加右括号 84 if(hasKuoHao == 1){ 85 for(int k = 0;k > brackets[j];k--){ 86 yunSuanShiTemp += ")"; 87 } 88 } 89 //如果不是最后一个运算数则要加上运算符 90 if(j != length - 1){ 91 yunSuanShiTemp += operatorSymbol[j]; 92 } 93 } 94 95 //计算结果 96 String answer = expressCalculate(yunSuanShiTemp, hasFuShu, hasYuShu, type, length - 1); 97 if((answer.equals("ERROR"))){ 98 continue; 99 } 100 yunSuanShiTemp += "=" + answer; 101 //检验重复 102 boolean chongFu = false; 103 for(int j = 0;j < i;j++){ 104 if((yunSuanShiArray[j].equals(yunSuanShiTemp))){ 105 chongFu = true; 106 break; 107 } 108 } 109 if(chongFu == false){ 110 yunSuanShiArray[i++] = yunSuanShiTemp; 111 } 112 } 113 return yunSuanShiArray; 114 } 115 116 //表达式计算,参数为字符串类型的运算式 117 public static String expressCalculate(String express,int hasFuShu,int hasYuShu,int type,int symbolNum){ 118 Stack<String> num = new Stack<String>(); 119 Stack<String> symbolS = new Stack<String>(); 120 symbolS.push("#"); 121 express += "#"; 122 char ch; 123 int i = 0; 124 int s = 0; 125 ch = express.charAt(i); 126 while(s < symbolNum){ 127 if(ch == ' '){//读到空格,说明开始读运算数 128 String readNumStr = ""; 129 while(true){ 130 ch = express.charAt(++i); 131 if(ch == ' '){ 132 break; 133 } 134 readNumStr += ch; 135 136 } 137 if((i + 1) < express.length()){ 138 ch = express.charAt(++i); 139 } 140 num.push(readNumStr); 141 }else{//读到的是运算符 142 char compare = priorityCompare(symbolS.peek(),ch + ""); 143 144 if(compare == '='){//如果是右括号 145 symbolS.pop(); 146 ch = express.charAt(++i); 147 }else if(compare == '>'){//ch的优先级小于栈顶的优先级 比栈顶的优先级高就不算,入栈,低就弹栈运算 148 //弹出两个运算数,弹出一个运算符 149 String bStr = num.pop(); 150 String aStr = num.pop(); 151 String symbolT = symbolS.pop(); 152 String c = yunSuan(aStr,bStr,symbolT,hasFuShu,hasYuShu,type); 153 if(c.equals("ERROR")){ 154 return "ERROR"; 155 }else if(c.indexOf("余") >= 0 && s != symbolNum - 1){//有余数 156 return "ERROR"; 157 }else{ 158 num.push(c); 159 } 160 s++; 161 }else{ 162 symbolS.push(ch + ""); 163 if((i + 1) < express.length()){ 164 ch = express.charAt(++i); 165 } 166 } 167 168 } 169 } 170 return num.pop(); 171 } 172 173 public static String yunSuan(String aStr,String bStr,String symbol,int hasFuShu,int hasYuShu,int type){ 174 if(type == 0){//整数 175 int a = Integer.parseInt(aStr); 176 int b = Integer.parseInt(bStr); 177 if(symbol.equals("+")){ 178 return "" + (a + b); 179 }else if(symbol.equals("-")){ 180 if(a - b < 0 && hasFuShu == 0){ 181 return "ERROR"; 182 }else{ 183 return "" + (a - b); 184 } 185 }else if(symbol.equals("*")){ 186 return "" + (a * b); 187 }else{ 188 if(b == 0){ 189 return "ERROR"; 190 } 191 if(a % b == 0){ 192 return "" + (a / b); 193 }else{ 194 if(hasYuShu == 1){ 195 return (a / b) + "余" + (a % b); 196 }else{ 197 return "ERROR"; 198 } 199 } 200 } 201 }else{//分数 202 String[] af = aStr.split("/"); 203 String[] bf = bStr.split("/"); 204 if(af[0].equals("0") || bf[0].equals("0")){ 205 return "ERROR"; 206 } 207 FenShu a = new FenShu(Integer.parseInt(af[1]),Integer.parseInt(af[0])); 208 FenShu b = new FenShu(Integer.parseInt(bf[1]),Integer.parseInt(bf[0])); 209 if(symbol.equals("+")){ 210 return a.add(b).toString(); 211 }else if(symbol.equals("-")){ 212 FenShu c = a.subtract(b); 213 if(hasFuShu == 1 && c.getNumerator() < 0){ 214 return "ERROR"; 215 } 216 return c.toString(); 217 }else if(symbol.equals("*")){ 218 return a.multiply(b).toString(); 219 }else{ 220 return a.divide(b).toString(); 221 } 222 } 223 } 224 //判断优先级 225 public static char priorityCompare(String a,String b){ 226 char[][] priority = { 227 {'>','>','<','<','<','>','>'}, 228 {'>','>','<','<','<','>','>'}, 229 {'>','>','>','>','<','>','>'}, 230 {'>','>','>','>','<','>','>'}, 231 {'<','<','<','<','<','=','>'}, 232 {'>','>','>','>',' ','>','>'}, 233 {'<','<','<','<','<',' ','='} 234 }; 235 int a_index = index_symbol(a); 236 int b_index = index_symbol(b); 237 return priority[a_index][b_index]; 238 } 239 240 public static int index_symbol(String a){ 241 String p = "+-*/()#"; 242 return p.indexOf(a); 243 } 244 245 //随机生成括号,参数为运算式的运算数的个数 246 public static int[] randomAddBracket(int length){ 247 int[] brackets = new int[length]; 248 for(int i = 0;i < brackets.length;i++) brackets[i] = 0; 249 Random rd = new Random(); 250 for(int i = 2;i < length;i++){//添加的括号长度(括号包围的运算数的个数) 251 for(int j = 0;j < length - i + 1;j++){ 252 int t = rd.nextInt(2);//随机生成0或1,0代表不加括号,1代表加括号 253 if(t == 1){ 254 if(brackets[j] >= 0 && brackets[j + i - 1] <= 0){//要加的括号的第一个运算数周围没有右括号,且 最后一个运算数周围没有左括号 255 int counteract = 0; 256 for(int k = j;k < j + i;k++){//将要加的括号之间的所有运算数对应的brackets相加, 257 //如果和为0说明这个括号之间的括号是匹配的,不会出现括号交叉现象 258 counteract += brackets[k]; 259 } 260 if(counteract == 0){ 261 brackets[j]++; 262 brackets[j + i - 1]--; 263 } 264 } 265 } 266 } 267 } 268 return brackets; 269 } 270 271 //随机生成一个运算数( type==0代表生成整数,type==1代表生成真分数,maxNum代表数值范围 0-(maxNum-1) ) 272 public static String getOperatorNumber(int type,int maxNum){ 273 Random rd = new Random(); 274 int a; 275 while(true){ 276 a = rd.nextInt(maxNum); 277 if(type == 0){//随机生成一个整数 278 return "" + a; 279 }else{//随机生成一个真分数 280 if(a == 0){ 281 continue; 282 } 283 int b = rd.nextInt(a); 284 FenShu c = new FenShu(a,b); 285 return c.toString(); 286 } 287 } 288 } 289 290 291 292 }
FenShu类
1 package test; 2 3 public class FenShu { 4 private int denominator,numerator; 5 6 public int getDenominator() { 7 return denominator; 8 } 9 10 public void setDenominator(int denominator) { 11 this.denominator = denominator; 12 } 13 14 public int getNumerator() { 15 return numerator; 16 } 17 18 public void setNumerator(int numerator) { 19 this.numerator = numerator; 20 } 21 22 public FenShu(int denominator, int numerator) { 23 this.denominator = denominator; 24 this.numerator = numerator; 25 yueJian(); 26 } 27 28 FenShu(){} 29 30 //约简 31 public void yueJian(){ 32 int y = 1; 33 for(int i = numerator;i > 1;i--){ 34 if(numerator % i == 0 && denominator % i == 0){ 35 y = i; 36 break; 37 } 38 } 39 // int nc = numerator,dc = denominator; 40 // if(nc != 0){ 41 // while(nc != dc - nc){ 42 // y = dc - nc; 43 // if(nc > y){ 44 // dc = nc; 45 // nc = y; 46 // }else{ 47 // dc = y; 48 // } 49 // } 50 // y = nc; 51 // 52 numerator /= y; 53 denominator /= y; 54 55 } 56 57 //加 58 public FenShu add(FenShu b){ 59 FenShu c = null; 60 int nNumerator = this.numerator * b.getDenominator() + this.denominator * b.getNumerator(); 61 int nDenominator = this.denominator * b.getDenominator(); 62 c = new FenShu(nDenominator,nNumerator); 63 return c; 64 } 65 66 //减 67 public FenShu subtract(FenShu b){ 68 FenShu c = null; 69 int nNumerator = this.numerator * b.getDenominator() - this.denominator * b.getNumerator(); 70 int nDenominator = this.denominator * b.getDenominator(); 71 c = new FenShu(nDenominator,nNumerator); 72 return c; 73 } 74 75 //乘 76 public FenShu multiply(FenShu b){ 77 FenShu c = null; 78 int nNumerator = this.numerator * b.getNumerator(); 79 int nDenominator = this.denominator * b.getDenominator(); 80 c = new FenShu(nDenominator,nNumerator); 81 return c; 82 } 83 84 //除 85 public FenShu divide(FenShu b){ 86 FenShu c = null; 87 int nNumerator = this.numerator * b.getDenominator(); 88 int nDenominator = this.denominator * b.getNumerator(); 89 c = new FenShu(nDenominator,nNumerator); 90 return c; 91 } 92 93 //输出分数形式 94 public String toString(){ 95 if(numerator != 0){ 96 // if(numerator % denominator == 0) 97 // return "" + numerator / denominator; 98 return numerator + "/" + denominator; 99 } 100 return "0"; 101 } 102 103 }
运行结果截图:
PSP0级过程文档
项目计划总结:
时间记录日志
缺陷记录日志