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、随机生成表达式:

 package Myapp;
 import java.util.ArrayList;
 import java.util.Random;
 import java.util.Scanner;

 public class utilClass {
     public static char[] operate={'+','-','*','÷'};
     public static String final_str;//四则运算表达式
     /**
      * 获取输入
      * @return
      */
     public static String getScanner(){
         Scanner scan=new Scanner(System.in);
         String input=scan.nextLine();
         scan.close();
         return input;
     }

     /**
      * 随机获取运算符+ - * ÷
      * @return
      */
     public static char getOperate(){
         Random rand=new Random();
         int operateNum=rand.nextInt(4);
         //System.out.println(operate[operateNum]);
         return operate[operateNum];
     }

     /**
      * 获取操作数
      * @param range 数值范围
      * @return
      */
     public static String getNumber(int range){
         Random rand=new Random();
         int index=rand.nextInt(3);
         String num="";

         /**
          * 随机获取数字,0获取自然数,1获取真分数,2获取带分数
          */
         if(index==0){//自然数
             Random rand0=new Random();
             num=rand0.nextInt(range-1)+1+"";
         }
         if(index==1){//真分数
             Random rand1=new Random();
             int denominator=rand1.nextInt(range-2)+2;//分母[2,range)
             int numerator=rand1.nextInt(denominator-1)+1;//分子
             num=numerator+"/"+denominator+"";
             /*System.out.println(denominator);
             System.out.println(numerator);
             System.out.println(num);*/
         }
         if(index==2){//带分数
             Random rand2=new Random();
             int leftNum=rand2.nextInt(range-1)+1;//左整数部分
             int rightDeno=rand2.nextInt(range-2)+2;//右真分数部分-分母[2,range)
             int rightNume=rand2.nextInt(rightDeno-1)+1;//右真分数部分-分子
             num=leftNum+"'"+rightNume+"/"+rightDeno+"";
         }
         //System.out.println(num);
         return num;
     }

     /**
      * 去表达式最前和最后的括号
      * @param str表达式
      * @return
      */
     public static String deleteParen(String str){
         if((str.substring(0, 1).equals("(")) && (str.substring(str.length()-1).equals(")"))){
             str=str.substring(1, str.length()-1);
         }
         return str;
     }

     /**
      * 生成四则运算表达式
      * range题目中操作数的范围
      */
     public static ArrayList<String> creatAc(int range){
         Random rand4=new Random();
         ArrayList<String> list=new ArrayList<String>();//存放每个表达式中的运算符和操作数
         boolean openParen=false;//左括号
         boolean closeParen=false;//右括号
         boolean tem=false;
         int operateNum=rand4.nextInt(3)+1;//每个表达式运算符个数1-3个
         final_str="";

         //------------开始生成--------------
         for(int j=0;j<operateNum;j++){

             //决定是否加入左括号
             if(!openParen && rand4.nextBoolean()){
                 final_str+="(";
                 list.add("(");
                 openParen=true;
             }
             String num1=getNumber(range);
             final_str+=num1;
             list.add(num1);
             //决定是否加入右括号
             if(openParen && !closeParen && tem){
                 if(rand4.nextBoolean()){
                     final_str+=")";
                     list.add(")");
                     closeParen=true;
                 }
             }
             char char1=getOperate();
             final_str+=char1;
             list.add(char1+"");
             if(openParen){
                 tem=true;
             }
         }
         String num2=getNumber(range);
         final_str+=num2;
         list.add(num2);
         if(openParen && !closeParen){
             final_str+=")";
             list.add(")");
         }
         final_str=deleteParen(final_str);//去掉开头和结尾均为括号
         //------------结束生成--------------

         System.out.println("中途生成"+final_str);
         return list;

     }

 }

2、生成后缀表达式

 package Myapp;

 import java.util.ArrayList;
 import java.util.Stack;

 public class RPN {

     /**
      *  将中序表达式转换成后序表达式
      * @param str 生成的中序表达式
      */
     public static Stack<String> toRPN(ArrayList<String> list){
         Stack<String> stack=new Stack<String>();//栈
         Stack<String> right=new Stack<String>();//右序表达式
         String operate;//运算符

         for(int i=0;i<list.size();i++){
             String ch=list.get(i);
 //            System.out.println(ch);
             if(isOperator(ch)){//当前字符为运算符
                 if(stack.empty()==true || ch=="("){//栈为空或者为(直接入栈
                     stack.push(ch);
 //                    System.out.println("栈为空或者为(直接入栈" + ch);
 //                    System.out.println(stack.peek());
                 }else{//非栈空、非左括号
 //                    System.out.println("非栈空、非左括号"+ch);
                     if(ch==")"){//如果为)
                         while(true){//将(后的运算符出栈并加到后续表达式中
 //                            System.out.println("111");
                             if((!stack.empty()) && (!stack.peek().equals("("))){
 //                                System.out.println("111111");
                                 operate=stack.pop();
 //                                System.out.println(operate);
                                 right.push(operate);
                             }else{
                                 if(!stack.empty())//如果栈顶元素为(
                                     stack.pop();
                                 break;
                             }
                         }
                     }else{//非栈空、非左括号、非右括号
 //                        System.out.println(0);
                         while(true){//栈不为空,优先级低
 //                            System.out.println(2);
                             if(!stack.empty() && priority(ch,stack.peek())){
                                 operate=stack.pop()+"";
 //                                System.out.println(22);
 //                                System.out.println(operate);
                                 if(!operate.equals("(")){
                                     right.push(operate);
                                 }
                             }else{
                                 break;
                             }
                         }
                         stack.push(ch+"");
                     }
                 }

             }else{
                 right.push(ch+"");//操作数
             }
         }
         while(!stack.empty()){
             operate=stack.pop()+"";
             if(!operate.equals("("))
                 right.push(operate);
         }

 //        Stack<String> newRight = new Stack<>();
 //        while (!right.isEmpty()) {
 //            System.out.print(right.peek());
 //            newRight.push(right.pop());
 //        }
 //        System.out.println();
 //        System.out.println(right.peek());
 //        System.out.println();
         return right;
     }

     /**
      * 判断是否为运算符
      */
     public static boolean isOperator(String ch){
         if((ch.equals("+"))||(ch.equals("-"))||(ch.equals("*"))||(ch.equals("÷"))||(ch.equals("("))||(ch.equals(")")))
             return true;
         else
             return false;
     }

     /**
      * 设置运算符的优先级别
      * @param operatorout当前中序表达式字符
      * @param operatorin栈中字符
      * @return
      */
     public static boolean priority(String operatorout, String operatorin) {
         int m = -1, n = -1;
         String addop[][] = { { "+", "-", "*", "÷", "(", ")" },
                 { "+", "-", "*", "÷", "(", ")" } };
         int first[][] = { { 1, 1, 2, 2, 2, 0 }, { 1, 1, 2, 2, 2, 0 },
                 { 1, 1, 1, 1, 2, 0 }, { 1, 1, 1, 1, 2, 0 },
                 { 2, 2, 2, 2, 2, 0 }, { 2, 2, 2, 2, 2, 2 } };
         for (int i = 0; i < 6; i++) {
             if (operatorin.equalsIgnoreCase(addop[0][i]))
                 m = i;
         }
         for (int i = 0; i < 6; i++) {
             if (operatorout.equalsIgnoreCase(addop[1][i]))
                 n = i;
         }
         if (m == -1 && n == -1)
             return false;
         else if (m == -1 && n != -1)
             return false;
         else if (m != -1 && n == -1)
             return true;
         else if (first[m][n] == 1) {
             return true;
         } else
             return false;
     }
 }

3、将表达式中所有数值转为分数形式

 package Myapp;
 import java.util.Stack;

 /*
  * 该类将后续表达式stack转化为有分子分母的后续表达式
  * 存于handleStack对象的calculatorStack中
  */
 public class handleStack {
 Stack<Node> posfixStack;

     public handleStack(Stack<String> stack) {
         // TODO Auto-generated constructor stub
         Stack<Node> stack1 = new Stack<>();//中间栈
         Stack<Node> stack2 = new Stack<>();//中间栈
         //String s;
         while(!stack.isEmpty()){
             String string = stack.pop();
             //运算符直接进栈
             if(string.equals("+")||string.equals("-")||string.equals("*")||string.equals("÷")){
                 Node node = new Node(true,string);
                 stack1.push(node);
             }
             else if(!string.contains("/")){
                 string = string + "/1";
                 Node node = new Node(false,string);
                 stack1.push(node);
             }
             else {
                 Node calculator = new Node(false,string);
                 stack1.push(calculator);
             }
         }
         for(Node c:stack1){
             stack2.push(c);
         }
         this.posfixStack = stack2;
 //        for(Calculator c:this.calculatorStack){
 //            System.out.println(c.operator + c.numerator + "/" + c.denominator);
 //        }
     }
 }

4、表达式计算

 package Myapp;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Stack;

 import org.jcp.xml.dsig.internal.MacOutputStream;

 import com.sun.javafx.collections.MappingChange.Map;
 import com.sun.org.apache.regexp.internal.recompile;

 public class Node {

     private static final int String = 0;
     Integer numerator;//分子
     Integer denominator;//分母
     boolean isOperator;
     String operator;
     Node lChild;
     Node rChild;

     //运算符构造方法
     public Node(boolean isOperator,String stackElement) {
         // TODO Auto-generated constructor stub
         if(isOperator == true){//为运算符
             this.isOperator = true;
             this.operator = stackElement;
         }
         else if (isOperator == false && stackElement.contains("'")){//为带分数
 //            System.out.println(stackElement);
             String[] split1 = stackElement.split("'");
             String[] split2 = split1[1].split("\\/");
             this.numerator = Integer.parseInt(split1[0])*Integer.parseInt(split2[1])
                     + Integer.parseInt(split2[0]);
             this.denominator = Integer.parseInt(split2[1]);
 //            System.out.println(numerator);
 //            System.out.println(denominator);
         }
         else if(isOperator == false && (!stackElement.contains("'"))){//为分数
 //            System.out.println(stackElement);
             String[] s = stackElement.split("\\/");
             this.numerator = Integer.parseInt(s[0]);
 //            System.out.println(numerator+"feafa");
             this.denominator = Integer.parseInt(s[1]);
 //            System.out.println(denominator);
         }
     }

     public Node(boolean isOperator,Integer num,Integer den) {
         // TODO Auto-generated constructor stub
         this.isOperator = isOperator;
         this.denominator = den;
         this.numerator = num;

     }

     public Node() {
         // TODO Auto-generated constructor stub
     }

     /*
      * 根据后缀表达式(分子分母形式)计算
      * 返回运算结果存于stack2中
      */
     public Stack<Node> calculate(Stack<Node> stackOld){
         Stack<Node> stack=(Stack<Node>) stackOld.clone();
         Stack<Node> stack2 = new Stack<>();
         Node calculator;
         while(!stack.isEmpty()){
             if(!(calculator = stack.pop()).isOperator){//操作数直接入栈
 //                System.out.println("??"+calculator.numerator + "/"+ calculator.denominator);
                 stack2.push(calculator);
             }
             else  if(calculator.isOperator){//若为运算符

                 //每次去除栈顶两个元素
                 Node calculator1 = stack2.pop();
                 Node calculator2 = stack2.pop();

                 switch (calculator.operator) {
                 case "+":
                     stack2.push(calculator.add(calculator2, calculator1));
                     break;

                 case "-":
                     Node res=calculator.sub(calculator2, calculator1);
                     if(res.numerator>0){
                         stack2.push(res);
                     }else{
                         res.operator="#";
                         stack2.push(res);
                         return stack2;
                     }
                     stack2.push(calculator.sub(calculator2, calculator1));
                     break;

                 case "*":
                     stack2.push(calculator.mul(calculator2, calculator1));
                     break;

                 case "÷":
                     stack2.push(calculator.div(calculator2, calculator1));
                     break;

                 default:
                     break;
                 }

             }
         }
         return stack2;
     }

     //加法
     public Node add(Node calculator1,Node calculator2) {
         Integer num = calculator1.numerator*calculator2.denominator +
                 calculator2.numerator*calculator1.denominator;
                 Integer den = calculator1.denominator*calculator2.denominator;
                 int g = gcd(num, den);
                 Node calculator = new Node(false, num/g, den/g);
                 return calculator;
     }

     //减法
     public Node sub(Node calculator1,Node calculator2) {
         Integer num = calculator1.numerator*calculator2.denominator -
                 calculator2.numerator*calculator1.denominator;
         Integer den = calculator1.denominator*calculator2.denominator;
         int g = gcd(num, den);
         Node calculator = new Node(false, num/g, den/g);
         return calculator;
     }

     //乘法
     public Node mul(Node calculator1,Node calculator2) {
         Integer num = calculator1.numerator*calculator2.numerator;
         Integer den = calculator1.denominator*calculator2.denominator;
         int g = gcd(num, den);
         Node calculator = new Node(false, num/g, den/g);
         return calculator;
     }

     //除法
     public Node div(Node calculator1,Node calculator2) {
         Integer num = calculator1.numerator*calculator2.denominator;
         Integer den = calculator1.denominator*calculator2.numerator;
         int g = gcd(num, den);
         Node calculator = new Node(false, num/g, den/g);
         return calculator;
     }

     //最大公约数
     public int gcd(int a, int b){
         int m = Math.max(Math.abs(a), Math.abs(b));
         int n = Math.min(Math.abs(a), Math.abs(b));
         int r;
         while(n!=0){
             r = m % n;
             m = n;
             n = r;
         }
         return m;
     }

     //比较两个分数数大小
     /**
      *
      * @param f1
      * @param f2
      * @return     f1 > f2 返回 2
      *             f1 = f2返回1
      *             f1 < f2返回-1
      *             其他 返回0
      */
     public int compareFraction(Node f1,Node f2) {
         Node node = new Node();

         if (f1.isOperator||f2.isOperator) {
             System.out.println("请输入数字进行比较!");
             return 0;
         }
         Node compare = node.sub(f1, f2);//f1 - f2 结果为node类型
         int result = compare.numerator/compare.denominator;//f1 - f2的结果
         if (result == 0) {
             return 1;
         }
         else if (result > 0) {
             return 2;
         }
         else if (result < 0) {
             return -1;
         } 

         return 0;
     }

     /**
      *
      * @param o1
      * @param o2
      * @return     o1 > o2 return 2
      *             o1 = o2 return 1
      *             o1 < o2 return -1
      *             其他                 return 0
      */
     public int  compareOperator(Node o1,Node o2) {
         if (!o1.isOperator||!o2.isOperator) {
             System.out.println("请输入正确运算符!");
             return 0;
         }
         HashMap<String, Integer> priMap = new HashMap<>();
         priMap.put("+", 0);
         priMap.put("-", 0);
         priMap.put("*", 1);
         priMap.put("÷", 1);

         if (priMap.get(o1.operator) > priMap.get(o2.operator)) {
             //o1 高于 o2
             return 2;
         }
         else if (priMap.get(o1.operator) == priMap.get(o2.operator)) {
             //o1 低于o2
             return 1;
         }
         else if (priMap.get(o1.operator) < priMap.get(o2.operator)) {
             //o1等于o2
             return 1;
         }
         return 0;
     }

     //假分数转带分数输出
         public ArrayList<String> imTomix(ArrayList<Node> answerList) {
             ArrayList<String> arrayList = new ArrayList<>();
             for (int i = 0; i < answerList.size(); i++) {
                 if (answerList.get(i).isOperator) {
                     System.out.println("不是运算结果!");
                 }
                 else if (answerList.get(i).denominator == 1){//分母为1,分数= 分子的值
                     arrayList.add(answerList.get(i).numerator + "");
                 }
                 else if ((answerList.get(i).numerator == 0) ||(answerList.get(i).numerator == 0)) {//若分子为0,则分数为0
                     arrayList.add(answerList.get(i).numerator + "");
                 }
                 else if (answerList.get(i).numerator == answerList.get(i).denominator) {//分子等于分母,answer=1
                     arrayList.add(1+"");
                 }
                 else if (answerList.get(i).numerator%answerList.get(i).denominator == 0) {//分子能整除分母
                     arrayList.add(answerList.get(i).numerator/answerList.get(i).denominator + "");
                 }
                 else if((answerList.get(i).denominator!=0)&&answerList.get(i).numerator/answerList.get(i).denominator > 1) {//假分数,转带分数
                     arrayList.add(answerList.get(i).numerator/answerList.get(i).denominator + "'"
                             + answerList.get(i).numerator%answerList.get(i).denominator + "/" + answerList.get(i).denominator);
                 }
                 else {
                     arrayList.add(answerList.get(i).numerator + "/" + answerList.get(i).denominator + "");
                 }
             }
             return arrayList;
         }
 }

5、检查重复

 package Myapp;
 import java.util.ArrayList;
 import java.util.Stack;

 /**
  * 构造方法:生成查重表达式
  * @author LHY
  *
  */
 public class Repeat {
     /**
      * @param profixStack 后缀表达式栈
      */
     public Stack<Node> checkRepeat(Stack<Node> profixStack) {
         // TODO Auto-generated constructor stub
         Stack<Node> numberStack = new Stack<>(); //构造一个中间栈,存放数字
         Stack<Node> checkStack = new Stack<>(); //存放查重表达式栈

 //        System.out.println(1);
         Node bookNode = new Node(true, 0,0);
 //        System.out.println(2);
         Node node1 = new Node();
         Node node2 = new Node();
         while(!profixStack.isEmpty()){//扫描后缀表达式栈直至其为空
             Node proStack_top = profixStack.pop();//开始扫描第一个
             if (!proStack_top.isOperator&&!(proStack_top.numerator==0&&proStack_top.denominator==0)) {//若后缀表达式栈顶元素为数字。若非#则进numberStack
                     numberStack.push(proStack_top);
 //                    System.out.println(proStack_top);
             }
 //            else if (proStack_top.isOperator&&proStack_top.numerator==0&&proStack_top.denominator==0) {
 //                numberStack.pop();
 //            }
             else if (proStack_top.isOperator) {//后缀表达式栈顶为运算符,则进checkStack,再pop两个数字,并把#压进数字
                 checkStack.push(proStack_top);
                 if (numberStack.size() > 1) {
                     if (!(node1=numberStack.pop()).isOperator&&!(node1.numerator==0)&&!(node1.denominator==0)) {//非#
                         checkStack.push(node1);
                     }
                     if (!(node2=numberStack.pop()).isOperator&&!(node2.numerator==0)&&!(node2.denominator==0)) {
                         checkStack.push(node2);
                     }
                 }
                 numberStack.push(bookNode);
             }

         }//end while
         System.out.println("size"+checkStack.size());
         for(Node node:checkStack){
             if (node.isOperator) {
                 System.out.print(node.operator + " ");
             }else if(!node.isOperator){
                 System.out.print(node.numerator + "/" + node.denominator + " ");
             }
         }
         return checkStack;

     }

     public  boolean IsRepeat(Stack<Node> exp1,Stack<Node> exp2){
         Repeat repeat=new Repeat();
         //转成查重表达式
         ArrayList<Node> temp=new ArrayList<Node>();//中间存放栈1
         Node tempNode=new Node();//中间交换结点
         Stack<Node> checkRepeat1=repeat.checkRepeat(exp1);
         Stack<Node> checkRepeat2=repeat.checkRepeat(exp2);
         Stack<Node> newStack=new Stack<Node>();//交换后的新栈
         int lengthRe1=checkRepeat1.size();
         int lengthRe2=checkRepeat2.size();
         System.out.println(1);
         if(lengthRe1!=lengthRe2) return false;//若长度不相等,则表达式一定不同
         System.out.println(2);
         for(Node n:checkRepeat1){
             temp.add(n);
         }
         if (this.isEqual(checkRepeat1, checkRepeat2)) {//完全一样则返回true
             return true;
         }

         if(temp.get(0).operator.equals("+")||temp.get(0).operator.equals("*")){//只有加或乘的情况才可能出现 交换左右操作数当做重复的表达式
             tempNode=temp.get(1);
             temp.set(1, temp.get(2));
             temp.set(2, tempNode);
         }
         for(Node p:temp){
             newStack.push(p);
         }
         if(this.isEqual(newStack, checkRepeat2)) return true;//若交换后也相等则重复
         System.out.println(3);
         return false;
     }

     public boolean  isEqual(Stack<Node> stack1,Stack<Node> stack2) {
         Stack<Node> s1 = new Stack<>();
         Stack<Node> s2 = new Stack<>();

         Node s1_top;
         Node s2_top;
         for(Node node1:stack1){
             s1.push(node1);
         }
         for(Node node2:stack2){
             s2.push(node2);
         }

         while (!s1.isEmpty()&&!s2.isEmpty()) {
             s1_top = s1.pop();
             s2_top = s2.pop();
             if (s1_top.isOperator) {//若s1栈顶为运算符
                 if (s2_top.isOperator&&(!s2_top.operator.equals(s1_top.operator))) {//s2都为运算符但s1不等于s2
                     return false;
                 }
                 else if (!s2_top.isOperator) {//s1为运算符,s2非运算符
                     return false;
                 }
             }
             else if (!s1_top.isOperator) {//若s1操作数
                 if (s2_top.isOperator) {//s2为运算符
                     return false;
                 }
                 else if (!s2_top.isOperator&&(s2_top.compareFraction(s1_top, s2_top)!=1)) {//s2为操作数但不等于s1
                 return false;
                 }
             }

         }
         return true;
     }
 }

6、满足非负及非重复条件生成表达式

 int count=0;
         ArrayList<String> finalExp=new ArrayList<>();//最终所有表达式
         ArrayList<Node> finalRes=new ArrayList<>();//最终所有结果(假分数)
         ArrayList<String> realRes =new ArrayList<>();//最终所有结果(真分数)
         ArrayList<Stack<Node>> checkArray=new ArrayList<>();//查重存放数组
         Repeat repeat=new Repeat();
         do {
             boolean flag=false;
             Stack<String> ac=new Stack<String>();
             ac=RPN.toRPN(utilClass.creatAc(range));//没带分母的后缀表达式
             handleStack handleStack=new handleStack(ac);//带分母的后缀表达式
             Node node=new Node();
             Stack<Node> stack=new Stack<Node>();
             stack=node.calculate(handleStack.posfixStack);//计算结果
             if(stack.peek().operator!="#"&&count==0){//非负,第一个表达式
                 checkArray.add(handleStack.posfixStack);
                 finalExp.add(utilClass.final_str);
                 finalRes.add(stack.peek());
                 count++;
             }
             if(stack.peek().operator!="#"&&count>0){//非负,第二个表达式开始
                 for(Stack<Node> p:checkArray){
                     if(repeat.isEqual(p, handleStack.posfixStack)){
                         flag=true;
                     }
                 }
                 if(!flag){
                     checkArray.add(handleStack.posfixStack);
                     finalExp.add(utilClass.final_str);
                     finalRes.add(stack.peek());
                     count++;
                 }
             }
         } while (count!=number);
         Node transNode=new Node();
         realRes=transNode.imTomix(finalRes);

7、文件读取

 package Myapp;

 import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.Reader;
 import java.util.ArrayList;

 import javax.imageio.spi.RegisterableService;

 import com.sun.swing.internal.plaf.basic.resources.basic_zh_TW;
 import com.sun.xml.internal.fastinfoset.util.StringIntMap;

 import sun.text.resources.BreakIteratorInfo;

 public class FileRW {

     /**
      * 将题目和答案写出在txt文件中
      * @param expList 题目集合
       * @param answerList 答案集合
      * @return  true 成功
      *             false 失败
      */
     public boolean fileWrite(ArrayList<String> expList,ArrayList<Node> answerList) {
         ArrayList<String>  outList = new ArrayList<>();
         if (expList.size()!=answerList.size()) {
             System.out.println("答案与题目数目不匹配!");
             return false;
         }

         for (int i = 0; i < expList.size(); i++) {
             System.out.println();
             outList.add(expList.get(i) + " = " +answerList.get(i).numerator + "/"+ answerList.get(i).denominator);
         }
         //开始写入文件
         try {
             BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"));
             for(String s:outList){
                 bw.write(s);
                 bw.newLine();
                 bw.flush();
             }
             bw.close();
         } catch (IOException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }

         return true;
     }

     /**
      * 把题目写出到文件
      * @param expList
      * @return
      */
     public File writeQ(ArrayList<String> expList) {
         int count = 1;
         File file = new File("Exercises.txt");
             try {
                 FileWriter fWriter = new FileWriter(file);
                 BufferedWriter bw = new BufferedWriter(fWriter);
                 for(String s:expList){
                     bw.write( count++ + "." +s);
                     bw.newLine();
                     bw.flush();
                 }
                 bw.close();
             } catch (IOException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
             return file;
     }

     /**
      * 把答案写出到文件
      * @param answerList
      * @return
      * @throws IOException
      */
     public File writeA(ArrayList<String> answerList) throws IOException {
         int count = 1;
         File file = new File("Answers.txt");
         FileWriter fWriter = new FileWriter(file);
         try {
             BufferedWriter bw = new BufferedWriter(fWriter);
             for(String s:answerList){
                 bw.write( count++ + "." +s);
                 bw.newLine();
                 bw.flush();
             }
             bw.close();
         } catch (IOException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
         return file;
     }

 /**
  *
  * @param answerFile 待检测文件
  * @param answerList 正确答案文件
  * @return
  */
     public File checkAnswer(File answerFile,File answerList) {

         try {
             BufferedReader rightReader = new BufferedReader(new FileReader(answerList));
             BufferedReader anserReader = new BufferedReader(new FileReader(answerFile));
             String rightString = null;
             String answerString = null;
             int right = 0;
             int wrong = 0;
             int line = 1;

             String Rnumber="";
             String Wnumber="";
             //比较对错
             while((rightString=rightReader.readLine())!=null&&(answerString=anserReader.readLine())!=null){
                 if(rightString.equals(answerString)){
                     right ++;
                     if (Rnumber.equals("")) {
                         Rnumber = Rnumber +line;
                     }
                     else{
                         Rnumber = Rnumber + ","+line;
                     }
                 }
                 else {
                     System.out.println(rightString);
                     System.out.println(answerString);
                     wrong++;
                     if (Wnumber.equals("")) {
                         Wnumber = Wnumber +line;
                     }else{
                         Wnumber = Wnumber + "," +line;
                     }
                 }
                 line++;
             }

             //写入到answerfile中
             BufferedWriter bw = new BufferedWriter(new FileWriter(answerFile, true));
             bw.newLine();
             bw.write("right: "+ right + " " + "("+ Rnumber +")" + ";");
             bw.newLine();
             bw.write("wrong: "+ wrong + " " + "("+ Wnumber + ")"+ ";");
             bw.flush();
             bw.close();

         } catch (FileNotFoundException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         } catch (IOException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }

         return answerFile;
     }

 }

五、测试截图

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) 蔡苑菲,陆海燕的更多相关文章

  1. 结对编程-四则运算生成器(java实现)

     结对伙伴:陈振华  项目要求 1.题目:实现一个自动生成小学四则运算题目的命令行程序. 2.需求: 1. 使用 -n 参数控制生成题目的个数 2. 使用 -r 参数控制题目中数值(自然数.真分数和真 ...

  2. 结对编程1----基于java的四则运算生成器

    小组成员:王震(201421123054).王杰(201421123055) Coding地址:https://git.coding.net/a506504661/sssss.git 一.题目描述 我 ...

  3. 结对编程--四则运算(Java)萧英杰 夏浚杰

    结对编程--四则运算(Java)萧英杰 夏浚杰 Github项目地址 功能要求 题目:实现一个自动生成小学四则运算题目的命令行程序 使用 -n 参数控制生成题目的个数(实现) 使用 -r 参数控制题目 ...

  4. 结对编程--四则运算(Java)梅进鹏 欧思良

    结对编程--四则运算(Java)梅进鹏 欧思良 Github项目地址:https://github.com/MeiJinpen/Arithmetic 功能要求 题目:实现一个自动生成小学四则运算题目的 ...

  5. 软工作业-四则运算(java实现)BY叶湖倩,叶钰羽

    四则运算生成器 BY-信安1班 叶湖倩(3216005170) 信安1班 叶钰羽(3216005171) 1. 项目介绍 源代码GitHub地址:https://github.com/yeyuyu/s ...

  6. 个人第二次作业-c++实现四则运算生成器

    c++实现四则运算生成器 GIT地址 Link Git用户名 Redwarx008 学号后五位 61128 博客地址 Link 作业链接 Link 环境配置 使用VS2019社区版,一键式安装,这里不 ...

  7. java四则运算生成器

    题目描述: 从<构建之法>第一章的 "程序" 例子出发,像阿超那样,花二十分钟写一个能自动生成小学四则运算题目的命令行 "软件",满足以下需求: 除 ...

  8. 小学四则运算生成器(Java) 刘少允,梁新男

    github传送门 项目相关要求 使用 -n 参数控制生成题目的个数.(实现) 使用 -r 参数控制题目中数值(自然数.真分数和真分数分母)的范围.(实现) 生成的题目中计算过程不能产生负数.(实现) ...

  9. 结对编程 四则运算(java)(胡大华 黄绪明)

    Github项目地址 https://github.com/yogurt1998/Myapp 项目需求 题目: 实现一个自动生成小学四则运算题目的命令行程序 功能 1.使用-n 参数控制生成题目的个数 ...

随机推荐

  1. CI 框架怎么去掉隐藏入口文件 index.php

    当我重新接触一个框架的时候首先肯定要去掉入口文件,也就是index.php 这个东西在url上很不漂亮,而且每次我访问我的网站的时候都要打进去url里面.这样告诉一个去掉 CI框架里面入口文件的方法, ...

  2. 文件计数--file_count.sh

    countFiles(){ path=$1 pathName=`ls $path` sum=0 for i in $pathName do num=`ls $path$i |wc -l` sum=$[ ...

  3. 怎么才知道你在使用的是不是中国电信CN2的线路

    原文:http://www.juzhenyun.org/helpview_66.html 首先你能从和电信的合同上确认是否为CN2线路 目前CN2的线路多为商业用途.公司用户申请中国电信的Intern ...

  4. CentOS6.5 安装mysql-5.7.9

    转自:http://forrest-lv.iteye.com/blog/2260703 安装前,需要检查是否已经有mysql服务进程,是否已经装过mysql;  这点很重要,我之前安装CentOS的同 ...

  5. web开发,click,touch,tap事件浅析

    一.click 和 tap 比较 两者都会在点击时触发,但是在手机WEB端,click会有 200~300 ms,所以请用tap代替click作为点击事件. singleTap和doubleTap 分 ...

  6. canvas变换

    canvas变换 方法 save() 保存canvas状态 restore() 回复canvas保存的状态 translate(x, y) 移动canvas位置 rotate(radians) 顺时针 ...

  7. 将一个list分为每份小鱼1000的

    List<LazadaTrackingDataTO> dataSourceList = new ArrayList<LazadaTrackingDataTO>();       ...

  8. Sublime Text 3 安装+注册+汉化

    参考:https://www.cnblogs.com/h--d/p/7555119.html

  9. gridview发布后,编辑改为edit 原因是未安装 dotNetFx40LP_Full_x86_x64zh-Hans中文语言包

    https://www.microsoft.com/zh-cn/download/details.aspx?id=3324

  10. 关闭 iTunes 自动同步

    关闭 iTunes 自动同步 iTunes>Edit>perererset>device>Prevent iPods,iPhone, and iPads from syncin ...