四则运算生成器(java) 蔡苑菲,陆海燕
Posted nancy12
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了四则运算生成器(java) 蔡苑菲,陆海燕相关的知识,希望对你有一定的参考价值。
github地址:https://github.com/Nancy0611/Myapp.git
一、项目相关要求
-
使用 -n 参数控制生成题目的个数,例如 Myapp.exe -n 10 将生成10个题目。(完成)
-
使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如 Myapp.exe -r 10 将生成10以内(不包括10)的四则运算题目。(完成)
-
生成的题目中计算过程不能产生负数,即算术表达式中如果存在形如e1 ? e2的子表达式,必须e1 ≥ e2。(完成)
- 生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数。(完成)
-
每道题目中出现的运算符个数不超过3个。(完成)
-
程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。(完成)
-
生成的题目存入执行程序的当前目录下的Exercises.txt文件,格式如下:(完成)
1. 四则运算题目1
2. 四则运算题目2
……
其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2‘3/8。
-
在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:(完成)
1. 答案1
2. 答案2
特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。
-
程序应能支持一万道题目的生成(完成)
-
程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,输入参数如下:(完成)
Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt 统计结果输出到文件Grade.txt,
格式如下: Correct: 5 (1, 3, 5, 7, 9)Wrong: 5 (2, 4, 6, 8, 10)
二、需求分析
从整体需求来看,大致可以分成三个模块:表达式生成模块、表达式运算模块、运算结果检验模块。
- 表达式生成模块:表达式包括运算符部分(加减乘除)、数字部分(自然数,真分数,带分数)、括号部分。数值部分利用random对象的nextInt方法随机从1开始生成,其中分子随机数的数值范围是比分母小1,保证生成的数字不出现假分数的情况;运算符的个数是利用函数随机生成1-3之间的自然数,加减乘除的符号也是利用随机数1-4来生成;符号部分利用next Boolean方法根据true或者false来决定括号的生成,该过程中利用一个变量来标记括号范围。
- 表达式运算模块:上述模块生成的表达式只是初步的表达式,运算功能是利用后缀表达式来实现的,生成后缀表达式后再将表达式的所有数值转化为分数形式,统一方便计算。为保证该过程中不出现负数运算,凡是进行减法运算的操作,都会对运算结果进行检验,一旦出现负数则丢弃当前表达式,直到再次生成的表达式符合要求,同时在此过程进行表达式的重复判断,将每一个当前非负表达式与已生成表达式进行查重检验,满足条件则加入Arraylist中,同时保存运算结果。
-
查重检验:将后缀表达式转换为查重表达式,查重表达式的结果为运算符在先,后面跟着该运算符的操作数,例如(1+2)*3-4,后缀表达式为:12+3*4-,按照查重表达式的结构为:+12*3-4,查重过程中只需要判断查重表达式是否一致,或者在查重表达式中第一个字符‘+‘或‘*‘的情况下后续的两个操作数交换位置后是否一致即可。也就是说+12*3-4与+21*3-4的表达式是一致的。举个表达式不重复的例子:1+2+3和3+2+1,查重表达式分别为+12+3和+32+1,查重表达式不相同,即使交换‘+‘后面的两个操作数也无法一致,故这两个表达式不重复。
-
-
运算结果检验模块:将最终符合要求的表达式存入当前目录下的Exercises.txt文件,正确答案保存在Answers.txt文件中,并对运算结果进行检。
三、设计思路
1、整体结构:
2、生成表达式思路:
四、模块代码说明
1、随机生成表达式:
1 package Myapp; 2 import java.util.ArrayList; 3 import java.util.Random; 4 import java.util.Scanner; 5 6 public class utilClass { 7 public static char[] operate={‘+‘,‘-‘,‘*‘,‘÷‘}; 8 public static String final_str;//四则运算表达式 9 /** 10 * 获取输入 11 * @return 12 */ 13 public static String getScanner(){ 14 Scanner scan=new Scanner(System.in); 15 String input=scan.nextLine(); 16 scan.close(); 17 return input; 18 } 19 20 /** 21 * 随机获取运算符+ - * ÷ 22 * @return 23 */ 24 public static char getOperate(){ 25 Random rand=new Random(); 26 int operateNum=rand.nextInt(4); 27 //System.out.println(operate[operateNum]); 28 return operate[operateNum]; 29 } 30 31 /** 32 * 获取操作数 33 * @param range 数值范围 34 * @return 35 */ 36 public static String getNumber(int range){ 37 Random rand=new Random(); 38 int index=rand.nextInt(3); 39 String num=""; 40 41 /** 42 * 随机获取数字,0获取自然数,1获取真分数,2获取带分数 43 */ 44 if(index==0){//自然数 45 Random rand0=new Random(); 46 num=rand0.nextInt(range-1)+1+""; 47 } 48 if(index==1){//真分数 49 Random rand1=new Random(); 50 int denominator=rand1.nextInt(range-2)+2;//分母[2,range) 51 int numerator=rand1.nextInt(denominator-1)+1;//分子 52 num=numerator+"/"+denominator+""; 53 /*System.out.println(denominator); 54 System.out.println(numerator); 55 System.out.println(num);*/ 56 } 57 if(index==2){//带分数 58 Random rand2=new Random(); 59 int leftNum=rand2.nextInt(range-1)+1;//左整数部分 60 int rightDeno=rand2.nextInt(range-2)+2;//右真分数部分-分母[2,range) 61 int rightNume=rand2.nextInt(rightDeno-1)+1;//右真分数部分-分子 62 num=leftNum+"‘"+rightNume+"/"+rightDeno+""; 63 } 64 //System.out.println(num); 65 return num; 66 } 67 68 /** 69 * 去表达式最前和最后的括号 70 * @param str表达式 71 * @return 72 */ 73 public static String deleteParen(String str){ 74 if((str.substring(0, 1).equals("(")) && (str.substring(str.length()-1).equals(")"))){ 75 str=str.substring(1, str.length()-1); 76 } 77 return str; 78 } 79 80 /** 81 * 生成四则运算表达式 82 * range题目中操作数的范围 83 */ 84 public static ArrayList<String> creatAc(int range){ 85 Random rand4=new Random(); 86 ArrayList<String> list=new ArrayList<String>();//存放每个表达式中的运算符和操作数 87 boolean openParen=false;//左括号 88 boolean closeParen=false;//右括号 89 boolean tem=false; 90 int operateNum=rand4.nextInt(3)+1;//每个表达式运算符个数1-3个 91 final_str=""; 92 93 //------------开始生成-------------- 94 for(int j=0;j<operateNum;j++){ 95 96 //决定是否加入左括号 97 if(!openParen && rand4.nextBoolean()){ 98 final_str+="("; 99 list.add("("); 100 openParen=true; 101 } 102 String num1=getNumber(range); 103 final_str+=num1; 104 list.add(num1); 105 //决定是否加入右括号 106 if(openParen && !closeParen && tem){ 107 if(rand4.nextBoolean()){ 108 final_str+=")"; 109 list.add(")"); 110 closeParen=true; 111 } 112 } 113 char char1=getOperate(); 114 final_str+=char1; 115 list.add(char1+""); 116 if(openParen){ 117 tem=true; 118 } 119 } 120 String num2=getNumber(range); 121 final_str+=num2; 122 list.add(num2); 123 if(openParen && !closeParen){ 124 final_str+=")"; 125 list.add(")"); 126 } 127 final_str=deleteParen(final_str);//去掉开头和结尾均为括号 128 //------------结束生成-------------- 129 130 System.out.println("中途生成"+final_str); 131 return list; 132 133 } 134 135 136 }
2、生成后缀表达式
1 package Myapp; 2 3 import java.util.ArrayList; 4 import java.util.Stack; 5 6 public class RPN { 7 8 /** 9 * 将中序表达式转换成后序表达式 10 * @param str 生成的中序表达式 11 */ 12 public static Stack<String> toRPN(ArrayList<String> list){ 13 Stack<String> stack=new Stack<String>();//栈 14 Stack<String> right=new Stack<String>();//右序表达式 15 String operate;//运算符 16 17 for(int i=0;i<list.size();i++){ 18 String ch=list.get(i); 19 // System.out.println(ch); 20 if(isOperator(ch)){//当前字符为运算符 21 if(stack.empty()==true || ch=="("){//栈为空或者为(直接入栈 22 stack.push(ch); 23 // System.out.println("栈为空或者为(直接入栈" + ch); 24 // System.out.println(stack.peek()); 25 }else{//非栈空、非左括号 26 // System.out.println("非栈空、非左括号"+ch); 27 if(ch==")"){//如果为) 28 while(true){//将(后的运算符出栈并加到后续表达式中 29 // System.out.println("111"); 30 if((!stack.empty()) && (!stack.peek().equals("("))){ 31 // System.out.println("111111"); 32 operate=stack.pop(); 33 // System.out.println(operate); 34 right.push(operate); 35 }else{ 36 if(!stack.empty())//如果栈顶元素为( 37 stack.pop(); 38 break; 39 } 40 } 41 }else{//非栈空、非左括号、非右括号 42 // System.out.println(0); 43 while(true){//栈不为空,优先级低 44 // System.out.println(2); 45 if(!stack.empty() && priority(ch,stack.peek())){ 46 operate=stack.pop()+""; 47 // System.out.println(22); 48 // System.out.println(operate); 49 if(!operate.equals("(")){ 50 right.push(operate); 51 } 52 }else{ 53 break; 54 } 55 } 56 stack.push(ch+""); 57 } 58 } 59 60 }else{ 61 right.push(ch+"");//操作数 62 } 63 } 64 while(!stack.empty()){ 65 operate=stack.pop()+""; 66 if(!operate.equals("(")) 67 right.push(operate); 68 } 69 70 // Stack<String> newRight = new Stack<>(); 71 // while (!right.isEmpty()) { 72 // System.out.print(right.peek()); 73 // newRight.push(right.pop()); 74 // } 75 // System.out.println(); 76 // System.out.println(right.peek()); 77 // System.out.println(); 78 return right; 79 } 80 81 /** 82 * 判断是否为运算符 83 */ 84 public static boolean isOperator(String ch){ 85 if((ch.equals("+"))||(ch.equals("-"))||(ch.equals("*"))||(ch.equals("÷"))||(ch.equals("("))||(ch.equals(")"))) 86 return true; 87 else 88 return false; 89 } 90 91 /** 92 * 设置运算符的优先级别 93 * @param operatorout当前中序表达式字符 94 * @param operatorin栈中字符 95 * @return 96 */ 97 public static boolean priority(String operatorout, String operatorin) { 98 int m = -1, n = -1; 99 String addop[][] = { { "+", "-", "*", "÷", "(", ")" }, 100 { "+", "-", "*", "÷", "(", ")" } }; 101 int first[][] = { { 1, 1, 2, 2, 2, 0 }, { 1, 1, 2, 2, 2, 0 }, 102 { 1, 1, 1, 1, 2, 0 }, { 1, 1, 1, 1, 2, 0 }, 103 { 2, 2, 2, 2, 2, 0 }, { 2, 2, 2, 2, 2, 2 } }; 104 for (int i = 0; i < 6; i++) { 105 if (operatorin.equalsIgnoreCase(addop[0][i])) 106 m = i; 107 } 108 for (int i = 0; i < 6; i++) { 109 if (operatorout.equalsIgnoreCase(addop[1][i])) 110 n = i; 111 } 112 if (m == -1 && n == -1) 113 return false; 114 else if (m == -1 && n != -1) 115 return false; 116 else if (m != -1 && n == -1) 117 return true; 118 else if (first[m][n] == 1) { 119 return true; 120 } else 121 return false; 122 } 123 }
3、将表达式中所有数值转为分数形式
1 package Myapp; 2 import java.util.Stack; 3 4 /* 5 * 该类将后续表达式stack转化为有分子分母的后续表达式 6 * 存于handleStack对象的calculatorStack中 7 */ 8 public class handleStack { 9 Stack<Node> posfixStack; 10 11 public handleStack(Stack<String> stack) { 12 // TODO Auto-generated constructor stub 13 Stack<Node> stack1 = new Stack<>();//中间栈 14 Stack<Node> stack2 = new Stack<>();//中间栈 15 //String s; 16 while(!stack.isEmpty()){ 17 String string = stack.pop(); 18 //运算符直接进栈 19 if(string.equals("+")||string.equals("-")||string.equals("*")||string.equals("÷")){ 20 Node node = new Node(true,string); 21 stack1.push(node); 22 } 23 else if(!string.contains("/")){ 24 string = string + "/1"; 25 Node node = new Node(false,string); 26 stack1.push(node); 27 } 28 else { 29 Node calculator = new Node(false,string); 30 stack1.push(calculator); 31 } 32 } 33 for(Node c:stack1){ 34 stack2.push(c); 35 } 36 this.posfixStack = stack2; 37 // for(Calculator c:this.calculatorStack){ 38 // System.out.println(c.operator + c.numerator + "/" + c.denominator); 39 // } 40 } 41 }
4、表达式计算
1 package Myapp; 2 import java.util.ArrayList; 3 import java.util.HashMap; 4 import java.util.Stack; 5 6 import org.jcp.xml.dsig.internal.MacOutputStream; 7 8 import com.sun.javafx.collections.MappingChange.Map; 9 import com.sun.org.apache.regexp.internal.recompile; 10 11 public class Node { 12 13 private static final int String = 0; 14 Integer numerator;//分子 15 Integer denominator;//分母 16 boolean isOperator; 17 String operator; 18 Node lChild; 19 Node rChild; 20 21 22 //运算符构造方法 23 public Node(boolean isOperator,String stackElement) { 24 // TODO Auto-generated constructor stub 25 if(isOperator == true){//为运算符 26 this.isOperator = true; 27 this.operator = stackElement; 28 } 29 else if (isOperator == false && stackElement.contains("‘")){//为带分数 30 // System.out.println(stackElement); 31 String[] split1 = stackElement.split("‘"); 32 String[] split2 = split1[1].split("\\/"); 33 this.numerator = Integer.parseInt(split1[0])*Integer.parseInt(split2[1]) 34 + Integer.parseInt(split2[0]); 35 this.denominator = Integer.parseInt(split2[1]); 36 // System.out.println(numerator); 37 // System.out.println(denominator); 38 } 39 else if(isOperator == false && (!stackElement.contains("‘"))){//为分数 40 // System.out.println(stackElement); 41 String[] s = stackElement.split("\\/"); 42 this.numerator = Integer.parseInt(s[0]); 43 // System.out.println(numerator+"feafa"); 44 this.denominator = Integer.parseInt(s[1]); 45 // System.out.println(denominator); 46 } 47 } 48 49 public Node(boolean isOperator,Integer num,Integer den) { 50 // TODO Auto-generated constructor stub 51 this.isOperator = isOperator; 52 this.denominator = den; 53 this.numerator = num; 54 55 } 56 57 public Node() { 58 // TODO Auto-generated constructor stub 59 } 60 61 /* 62 * 根据后缀表达式(分子分母形式)计算 63 * 返回运算结果存于stack2中 64 */ 65 public Stack<Node> calculate(Stack<Node> stackOld){ 66 Stack<Node> stack=(Stack<Node>) stackOld.clone(); 67 Stack<Node> stack2 = new Stack<>(); 68 Node calculator; 69 while(!stack.isEmpty()){ 70 if(!(calculator = stack.pop()).isOperator){//操作数直接入栈 71 // System.out.println("??"+calculator.numerator + "/"+ calculator.denominator); 72 stack2.push(calculator); 73 } 74 else if(calculator.isOperator){//若为运算符 75 76 //每次去除栈顶两个元素 77 Node calculator1 = stack2.pop(); 78 Node calculator2 = stack2.pop(); 79 80 switch (calculator.operator) { 81 case "+": 82 stack2.push(calculator.add(calculator2, calculator1)); 83 break; 84 85 case "-": 86 Node res=calculator.sub(calculator2, calculator1); 87 if(res.numerator>0){ 88 stack2.push(res); 89 }else{ 90 res.operator="#"; 91 stack2.push(res); 92 return stack2; 93 } 94 stack2.push(calculator.sub(calculator2, calculator1)); 95 break; 96 97 case "*": 98 stack2.push(calculator.mul(calculator2, calculator1)); 99 break; 100 101 case "÷": 102 stack2.push(calculator.div(calculator2, calculator1)); 103 break; 104 105 default: 106 break; 107 } 108 109 } 110 } 111 return stack2; 112 } 113 114 //加法 115 public Node add(Node calculator1,Node calculator2) { 116 Integer num = calculator1.numerator*calculator2.denominator + 117 calculator2.numerator*calculator1.denominator; 118 Integer den = calculator1.denominator*calculator2.denominator; 119 int g = gcd(num, den); 120 Node calculator = new Node(false, num/g, den/g); 121 return calculator; 122 } 123 124 //减法 125 public Node sub(Node calculator1,Node calculator2) { 126 Integer num = calculator1.numerator*calculator2.denominator - 127 calculator2.numerator*calculator1.denominator; 128 Integer den = calculator1.denominator*calculator2.denominator; 129 int g = gcd(num, den); 130 Node calculator = new Node(false, num/g, den/g); 131 return calculator; 132 } 133 134 //乘法 135 public Node mul(Node calculator1,Node calculator2) { 136 Integer num = calculator1.numerator*calculator2.numerator; 137 Integer den = calculator1.denominator*calculator2.denominator; 138 int g = gcd(num, den); 139 Node calculator = new Node(false, num/g, den/g); 140 return calculator; 141 } 142 143 //除法 144 public Node div(Node calculator1,Node calculator2) { 145 Integer num = calculator1.numerator*calculator2.denominator; 146 Integer den = calculator1.denominator*calculator2.numerator; 147 int g = gcd(num, den); 148 Node calculator = new Node(false, num/g, den/g); 149 return calculator; 150 } 151 152 //最大公约数 153 public int gcd(int a, int b){ 154 int m = Math.max(Math.abs(a), Math.abs(b)); 155 int n = Math.min(Math.abs(a), Math.abs(b)); 156 int r; 157 while(n!=0){ 158 r = m % n; 159 m = n; 160 n = r; 161 } 162 return m; 163 } 164 165 //比较两个分数数大小 166 /** 167 * 168 * @param f1 169 * @param f2 170 * @return f1 > f2 返回 2 171 * f1 = f2返回1 172 * f1 < f2返回-1 173 * 其他 返回0 174 */ 175 public int compareFraction(Node f1,Node f2) { 176 Node node = new Node(); 177 178 if (f1.isOperator||f2.isOperator) { 179 System.out.println("请输入数字进行比较!"); 180 return 0; 181 } 182 Node compare = node.sub(f1, f2);//f1 - f2 结果为node类型 183 int result = compare.numerator/compare.denominator;//f1 - f2的结果 184 if (result == 0) { 185 return 1; 186 } 187 else if (result > 0) { 188 return 2; 189 } 190 else if (result < 0) { 191 return -1; 192 } 193 194 return 0; 195 } 196 197 /** 198 * 199 * @param o1 200 * @param o2 201 * @return o1 > o2 return 2 202 * o1 = o2 return 1 203 * o1 < o2 return -1 204 * 其他 return 0 205 */ 206 public int compareOperator(Node o1,Node o2) { 207 if (!o1.isOperator||!o2.isOperator) { 208 System.out.println("请输入正确运算符!"); 209 return 0; 210 } 211 HashMap<String, Integer> priMap = new HashMap<>(); 212 priMap.put("+", 0); 213 priMap.put("-", 0); 214 priMap.put("*", 1); 215 priMap.put("÷", 1); 216 217 if (priMap.get(o1.operator) > priMap.get(o2.operator)) { 218 //o1 高于 o2 219 return 2; 220 } 221 else if (priMap.get(o1.operator) == priMap.get(o2.operator)) { 222 //o1 低于o2 223 return 1; 224 } 225 else if (priMap.get(o1.operator) < priMap.get(o2.operator)) { 226 //o1等于o2 227 return 1; 228 } 229 return 0; 230 } 231 232 //假分数转带分数输出 233 public ArrayList<String> imTomix(ArrayList<Node> answerList) { 234 ArrayList<String> arrayList = new ArrayList<>(); 235 for (int i = 0; i < answerList.size(); i++) { 236 if (answerList.get(i).isOperator) { 237 System.out.println("不是运算结果!"); 238 } 239 else if (answerList.get(i).denominator == 1){//分母为1,分数= 分子的值 240 arrayList.add(answerList.get(i).numerator + ""); 241 } 242 else if ((answerList.get(i).numerator == 0) ||(answerList.get(i).numerator == 0)) {//若分子为0,则分数为0 243 arrayList.add(answerList.get(i).numerator + ""); 244 } 245 else if (answerList.get(i).numerator == answerList.get(i).denominator) {//分子等于分母,answer=1 246 arrayList.add(1+""); 247 } 248 else if (answerList.get(i).numerator%answerList.get(i).denominator == 0) {//分子能整除分母 249 arrayList.add(answerList.get(i).numerator/answerList.get(i).denominator + ""); 250 } 251 else if((answerList.get(i).denominator!=0)&&answerList.get(i).numerator/answerList.get(i).denominator > 1) {//假分数,转带分数 252 arrayList.add(answerList.get(i).numerator/answerList.get(i).denominator + "‘" 253 + answerList.get(i).numerator%answerList.get(i).denominator + "/" + answerList.get(i).denominator); 254 } 255 else { 256 arrayList.add(answerList.get(i).numerator + "/" + answerList.get(i).denominator + ""); 257 } 258 } 259 return arrayList; 260 } 261 }
5、检查重复
1 package Myapp; 2 import java.util.ArrayList; 3 import java.util.Stack; 4 5 /** 6 * 构造方法:生成查重表达式 7 * @author LHY 8 * 9 */ 10 public class Repeat { 11 /** 12 * @param profixStack 后缀表达式栈 13 */ 14 public Stack<Node> checkRepeat(Stack<Node> profixStack) { 15 // TODO Auto-generated constructor stub 16 Stack<Node> numberStack = new Stack<>(); //构造一个中间栈,存放数字 17 Stack<Node> checkStack = new Stack<>(); //存放查重表达式栈 18 19 // System.out.println(1); 20 Node bookNode = new Node(true, 0,0); 21 // System.out.println(2); 22 Node node1 = new Node(); 23 Node node2 = new Node(); 24 while(!profixStack.isEmpty()){//扫描后缀表达式栈直至其为空 25 Node proStack_top = profixStack.pop();//开始扫描第一个 26 if (!proStack_top.isOperator&&!(proStack_top.numerator==0&&proStack_top.denominator==0)) {//若后缀表达式栈顶元素为数字。若非#则进numberStack 27 numberStack.push(proStack_top); 28 // System.out.println(proStack_top); 29 } 30 // else if (proStack_top.isOperator&&proStack_top.numerator==0&&proStack_top.denominator==0) { 31 // numberStack.pop(); 32 // } 33 else if (proStack_top.isOperator) {//后缀表达式栈顶为运算符,则进checkStack,再pop两个数字,并把#压进数字 34 checkStack.push(proStack_top); 35 if (numberStack.size() > 1) { 36 if (!(node1=numberStack.pop()).isOperator&&!(node1.numerator==0)&&!(node1.denominator==0)) {//非# 37 checkStack.push(node1); 38 } 39 if (!(node2=numberStack.pop()).isOperator&&!(node2.numerator==0)&&!(node2.denominator==0)) { 40 checkStack.push(node2); 41 } 42 } 43 numberStack.push(bookNode); 44 } 45 46 }//end while 47 System.out.println("size"+checkStack.size()); 48 for(Node node:checkStack){ 49 if (node.isOperator) { 50 System.out.print(node.operator + " "); 51 }else if(!node.isOperator){ 52 System.out.print(node.numerator + "/" + node.denominator + " "); 53 } 54 } 55 return checkStack; 56 57 } 58 59 public boolean IsRepeat(Stack<Node> exp1,Stack<Node> exp2){ 60 Repeat repeat=new Repeat(); 61 //转成查重表达式 62 ArrayList<Node> temp=new ArrayList<Node>();//中间存放栈1 63 Node tempNode=new Node();//中间交换结点 64 Stack<Node> checkRepeat1=repeat.checkRepeat(exp1); 65 Stack<Node> checkRepeat2=repeat.checkRepeat(exp2); 66 Stack<Node> newStack=new Stack<Node>();//交换后的新栈 67 int lengthRe1=checkRepeat1.size(); 68 int lengthRe2=checkRepeat2.size(); 69 System.out.println(1); 70 if(lengthRe1!=lengthRe2) return false;//若长度不相等,则表达式一定不同 71 System.out.println(2); 72 for(Node n:checkRepeat1){ 73 temp.add(n); 74 } 75 if (this.isEqual(checkRepeat1, checkRepeat2)) {//完全一样则返回true 76 return true; 77 } 78 79 if(temp.get(0).operator.equals("+")||temp.get(0).operator.equals("*")){//只有加或乘的情况才可能出现 交换左右操作数当做重复的表达式 80 tempNode=temp.get(1); 81 temp.set(1, temp.get(2)); 82 temp.set(2, tempNode); 83 } 84 for(Node p:temp){ 85 newStack.push(p); 86 } 87 if(this.isEqual(newStack, checkRepeat2)) return true;//若交换后也相等则重复 88 System.out.println(3); 89 return false; 90 } 91 92 public boolean isEqual(Stack<Node> stack1,Stack<Node> stack2) { 93 Stack<Node> s1 = new Stack<>(); 94 Stack<Node> s2 = new Stack<>(); 95 96 Node s1_top; 97 Node s2_top; 98 for(Node node1:stack1){ 99 s1.push(node1); 100 } 101 for(Node node2:stack2){ 102 s2.push(node2); 103 } 104 105 while (!s1.isEmpty()&&!s2.isEmpty()) { 106 s1_top = s1.pop(); 107 s2_top = s2.pop(); 108 if (s1_top.isOperator) {//若s1栈顶为运算符 109 if (s2_top.isOperator&&(!s2_top.operator.equals(s1_top.operator))) {//s2都为运算符但s1不等于s2 110 return false; 111 } 112 else if (!s2_top.isOperator) {//s1为运算符,s2非运算符 113 return false; 114 } 115 } 116 else if (!s1_top.isOperator) {//若s1操作数 117 if (s2_top.isOperator) {//s2为运算符 118 return false; 119 } 120 else if (!s2_top.isOperator&&(s2_top.compareFraction(s1_top, s2_top)!=1)) {//s2为操作数但不等于s1 121 return false; 122 } 123 } 124 125 } 126 return true; 127 } 128 }
6、满足非负及非重复条件生成表达式
1 int count=0; 2 ArrayList<String> finalExp=new ArrayList<>();//最终所有表达式 3 ArrayList<Node> finalRes=new ArrayList<>();//最终所有结果(假分数) 4 ArrayList<String> realRes =new ArrayList<>();//最终所有结果(真分数) 5 ArrayList<Stack<Node>> checkArray=new ArrayList<>();//查重存放数组 6 Repeat repeat=new Repeat(); 7 do { 8 boolean flag=false; 9 Stack<String> ac=new Stack<String>(); 10 ac=RPN.toRPN(utilClass.creatAc(range));//没带分母的后缀表达式 11 handleStack handleStack=new handleStack(ac);//带分母的后缀表达式 12 Node node=new Node(); 13 Stack<Node> stack=new Stack<Node>(); 14 stack=node.calculate(handleStack.posfixStack);//计算结果 15 if(stack.peek().operator!="#"&&count==0){//非负,第一个表达式 16 checkArray.add(handleStack.posfixStack); 17 finalExp.add(utilClass.final_str); 18 finalRes.add(stack.peek()); 19 count++; 20 } 21 if(stack.peek().operator!="#"&&count>0){//非负,第二个表达式开始 22 for(Stack<Node> p:checkArray){ 23 if(repeat.isEqual(p, handleStack.posfixStack)){ 24 flag=true; 25 } 26 } 27 if(!flag){ 28 checkArray.add(handleStack.posfixStack); 29 finalExp.add(utilClass.final_str); 30 finalRes.add(stack.peek()); 31 count++; 32 } 33 } 34 } while (count!=number); 35 Node transNode=new Node(); 36 realRes=transNode.imTomix(finalRes);
7、文件读取
1 package Myapp; 2 3 import java.io.BufferedReader; 4 import java.io.BufferedWriter; 5 import java.io.File; 6 import java.io.FileNotFoundException; 7 import java.io.FileReader; 8 import java.io.FileWriter; 9 import java.io.IOException; 10 import java.io.Reader; 11 import java.util.ArrayList; 12 13 import javax.imageio.spi.RegisterableService; 14 15 import com.sun.swing.internal.plaf.basic.resources.basic_zh_TW; 16 import com.sun.xml.internal.fastinfoset.util.StringIntMap; 17 18 import sun.text.resources.BreakIteratorInfo; 19 20 public class FileRW { 21 22 /** 23 * 将题目和答案写出在txt文件中 24 * @param expList 题目集合 25 * @param answerList 答案集合 26 * @return true 成功 27 * false 失败 28 */ 29 public boolean fileWrite(ArrayList<String> expList,ArrayList<Node> answerList) { 30 ArrayList<String> outList = new ArrayList<>(); 31 if (expList.size()!=answerList.size()) { 32 System.out.println("答案与题目数目不匹配!"); 33 return false; 34 } 35 36 for (int i = 0; i < expList.size(); i++) { 37 System.out.println(); 38 outList.add(expList.get(i) + " = " +answerList.get(i).numerator + "/"+ answerList.get(i).denominator); 39 } 40 //开始写入文件 41 try { 42 BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt")); 43 for(String s:outList){ 44 bw.write(s); 45 bw.newLine(); 46 bw.flush(); 47 } 48 bw.close(); 49 } catch (IOException e) { 50 // TODO Auto-generated catch block 51 e.printStackTrace(); 52 } 53 54 return true; 55 } 56 57 /** 58 * 把题目写出到文件 59 * @param expList 60 * @return 61 */ 62 public File writeQ(ArrayList<String> expList) { 63 int count = 1; 64 File file = new File("Exercises.txt"); 65 try { 66 FileWriter fWriter = new FileWriter(file); 67 BufferedWriter bw = new BufferedWriter(fWriter); 68 for(String s:expList){ 69 bw.write( count++ + "." +s); 70 bw.newLine(); 71 bw.flush(); 72 } 73 bw.close(); 74 } catch (IOException e) { 75 // TODO Auto-generated catch block 76 e.printStackTrace(); 77 } 78 return file; 79 } 80 81 /** 82 * 把答案写出到文件 83 * @param answerList 84 * @return 85 * @throws IOException 86 */ 87 public File writeA(ArrayList<String> answerList) throws IOException { 88 int count = 1; 89 File file = new File("Answers.txt"); 90 FileWriter fWriter = new FileWriter(file); 91 try { 92 BufferedWriter bw = new BufferedWriter(fWriter); 93 for(String s:answerList){ 94 bw.write( count++ + "." +s); 95 bw.newLine(); 96 bw.flush(); 97 } 98 bw.close(); 99 } catch (IOException e) { 100 // TODO Auto-generated catch block 101 e.printStackTrace(); 102 } 103 return file; 104 } 105 106 107 /** 108 * 109 * @param answerFile 待检测文件 110 * @param answerList 正确答案文件 111 * @return 112 */ 113 public File checkAnswer(File answerFile,File answerList) { 114 115 try { 116 BufferedReader rightReader = new BufferedReader(new FileReader(answerList)); 117 BufferedReader anserReader = new BufferedReader(new FileReader(answerFile)); 118 String rightString = null; 119 String answerString = null; 120 int right = 0; 121 int wrong = 0; 122 int line = 1; 123 124 String Rnumber=""; 125 String Wnumber=""; 126 //比较对错 127 while((rightString=rightReader.readLine())!=null&&(answerString=anserReader.readLine())!=null){ 128 if(rightString.equals(answerString)){ 129 right ++; 130 if (Rnumber.equals("")) { 131 Rnumber = Rnumber +line; 132 } 133 else{ 134 Rnumber = Rnumber + ","+line; 135 } 136 } 137 else { 138 System.out.println(rightString); 139 System.out.println(answerString); 140 wrong++; 141 if (Wnumber.equals("")) { 142 Wnumber = Wnumber +line; 143 }else{ 144 Wnumber = Wnumber + "," +line; 145 } 146 } 147 line++; 148 } 149 150 //写入到answerfile中 151 BufferedWriter bw = new BufferedWriter(new FileWriter(answerFile, true)); 152 bw.newLine(); 153 bw.write("right: "+ right + " " + "("+ Rnumber +")" + ";"); 154 bw.newLine(); 155 bw.write("wrong: "+ wrong + " " + "("+ Wnumber + ")"+ ";"); 156 bw.flush(); 157 bw.close(); 158 159 } catch (FileNotFoundException e) { 160 // TODO Auto-generated catch block 161 e.printStackTrace(); 162 } catch (IOException e) { 163 // TODO Auto-generated catch block 164 e.printStackTrace(); 165 } 166 167 return answerFile; 168 } 169 170 }
五、测试截图
1、10道题测试
命令行:
结果:
结果校对:
2、10000道题测试
命令行:
题目(部分题目)如下:
结果(部分结果)如下:
10000道题目链接:https://github.com/Nancy0611/Myapp/blob/master/Exercises.txt (÷该符号在githhub中乱码显示,未处理)
10000道题目答案:https://github.com/Nancy0611/Myapp/blob/master/Answers.txt
六、PSP时间统计
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 80 |
· Estimate | · 估计这个任务需要多少时间 | 30 | 60 |
Development | 开发 | 1050 | 1180 |
· Analysis | · 需求分析 (包括学习新技术) | 60 | 100 |
· Design Spec | · 生成设计文档 | 30 | 50 |
· Design Review | · 设计复审 (和同事审核设计文档) | 60 | 120 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 40 |
· Design | · 具体设计 | 240 | 300 |
· Coding | · 具体编码 | 800 | 900 |
· Code Review | · 代码复审 | 150 | 180 |
· Test | · 测试(自我测试,修改代码,提交修改) | 60 | 80 |
Reporting | 报告 | 180 | 200 |
· Test Report | · 测试报告 | 90 | 100 |
· Size Measurement | · 计算工作量 | 20 | 30 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 40 |
合计 | 2860 | 3460 |
七、项目总结
本次课程设计时间花费较多主要是在处理表达式以及检查表达式重复的问题,在查重时有尝试用二叉树解决,但由于前期设计生成表达式时没有用二叉树存储,仅用二叉树来查重代价略高,最后决定使用查重表达式进行处理,通过对初始表达式进行查重和查负判断,最终生成符合要求的表达式,因为中间的许多判断方法较为繁琐,生成一万道表达式花费的时间较长,目前未进行性能的优化。本次课设中对栈的使用较多,由于数据结构相关基础知识不是很扎实,在对栈进行遍历等操作时出现了较多问题,主要是栈顶栈底的顺序问题。由于四则运算中的数值类型有自然数 、真分数和带分数,在计算时较难统一,经讨论后决定将所有数值都转化为分数形式。在本次任务完成中,通过与队友的配合,相互学习,取长补短,加深了对java面向对象编程思想的理解,受益匪浅。
以上是关于四则运算生成器(java) 蔡苑菲,陆海燕的主要内容,如果未能解决你的问题,请参考以下文章
转载 WCDMA中码片速率符号速率bit速率 WCDMA常用概念