四则运算生成器(java) 蔡苑菲,陆海燕

Posted nancy12

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了四则运算生成器(java) 蔡苑菲,陆海燕相关的知识,希望对你有一定的参考价值。

github地址https://github.com/Nancy0611/Myapp.git

一、项目相关要求

  1. 使用 -n 参数控制生成题目的个数,例如 Myapp.exe -n 10 将生成10个题目。(完成)

  2. 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如 Myapp.exe -r 10 将生成10以内(不包括10)的四则运算题目。(完成)

  3. 生成的题目中计算过程不能产生负数,即算术表达式中如果存在形如e1 ? e2的子表达式,必须e1 ≥ e2。(完成)

  4. 生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数。(完成)
  5. 每道题目中出现的运算符个数不超过3个。(完成)

  6. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。(完成)

  7. 生成的题目存入执行程序的当前目录下的Exercises.txt文件,格式如下:(完成)

    1. 四则运算题目1

    2. 四则运算题目2

    ……

     其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2‘3/8。

  8. 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:(完成)

    1. 答案1

    2. 答案2

    特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。

  9. 程序应能支持一万道题目的生成(完成)

  10. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,输入参数如下:(完成)

    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.1Personal 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) 蔡苑菲,陆海燕的主要内容,如果未能解决你的问题,请参考以下文章

码片速率的含义

CDMA码片序列问题

转载 WCDMA中码片速率符号速率bit速率 WCDMA常用概念

码分复用

多式联运基于matlab粒子群结合遗传算法求解陆海空多式联运问题含Matlab源码 2061期

多式联运基于matlab粒子群结合遗传算法求解陆海空多式联运问题含Matlab源码 2061期