四则运算题目生成程序

 

  • a.需求分析:根据出版社要求,需要出版一本万题四则运算题以加强小学生计算能力。
    • 定义:
          自然数:0, 1, 2, …。
          真分数:1/2, 1/3, 2/3, 1/4, 11/2, …。
          运算符:+, −, ×, ÷。
          括号:(, )。
          等号:=。
          分隔符:空格(用于四则运算符和等号前后)。
          算术表达式:
                   e := n | e1 + e2 | e1 − e2 | e1 × e2 | e1 ÷ e2 | (e),
          其中e, e1和e2为表达式,n为自然数或真分数。
          四则运算题目:e = ,其中e为算术表达式。

       

  • b.功能设计:
    • 功能: 
        1.生成随机数n
        2.生成随机运算符
        3.组成算数表达式
        4.计算题目结果并输出文档
        5.比较答案并给出错误题号
      要求:
        1.表达式不重复
        2.结果无负数
        3.结果最简
        4.算符不超过三个

       

  • c.设计实现
  •  1.生成表达式
    2.求逆波兰式
    3.计算逆波兰式

     

  • d.代码说明

   算数表达式的生成:

  • import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    
    public class FormulaMake {
        int range; //最大运算数的范围
        int mount; //运算数的个数
        
        //构造函数
        public FormulaMake(int range, int mount) {
            super();
            this.range = range;
            this.mount = mount;
        }
        
        //返回两个数的最大公约数(测试通过)
        public int greatestCommonDivisor(int m,int n) {
            int temp,i;
            int theDivisor=0;
            if(m<n) {
                temp = m;
                m = n;
                n = temp;
            }
            for(i=n;i>0;i--) {
                if((m%i==0)&&(n%i==0)) {
                    theDivisor=i;
                    break;
                }
            }
            return theDivisor;
        }
        
        //数字生成
        public String createNum(int theRange) {
            theRange = getRange();
            NPR npr = new NPR();
            String theNumber = "";
            int numerator; //分子
            int denominator; //分母
            numerator = (int)(Math.random()*theRange)+1;
            denominator = (int)(Math.random()*theRange)+1;
            theNumber=npr.simpleNum(numerator, denominator);
            return theNumber;
        } 
    //随机生成含有n个数字的四则运算算式 public List fourArithmetic(int element) { int n = 0; String[] operatorArray = new String[] {"+","-","*","÷"};//存储运算符的数组 element = getMount(); //运算元数,随机生成2到6个运算元 List arithmeticArray = new ArrayList(); //存储数字和四则运算符的集合 while(n<element) { String theNum = createNum(getRange()); arithmeticArray.add(theNum); int theIndex = (int)(Math.random()*4); //运算符数组指针{0,1,2,3} arithmeticArray.add(operatorArray[theIndex]); n++; } //生成不带括号的表达式 int theLast = arithmeticArray.size()-1; //最后一个多出来的符号的指针 arithmeticArray.remove(theLast); //生成带括号的表达式 boolean flag = false; int probability = (int)(Math.random()*5)+1; //生成括号的概率 if(probability>3) {    //定义生成括号的概率为40% int theTemp = element-1; int insertPosition = (int)(Math.random()*theTemp);//插入左括号的合法位置 int leftInsertPosition = insertPosition*2; arithmeticArray.add(leftInsertPosition,"("); flag = true; //说明生成了左括号
    //插入右括号 int tempLeft = arithmeticArray.indexOf("("); if((tempLeft+4) != arithmeticArray.size()) { int tempAdd = (int)(Math.random()*2); tempAdd+=2; int tempRight = tempLeft+(tempAdd*2); arithmeticArray.add(tempRight,")"); }else { arithmeticArray.add(arithmeticArray.size(),")"); } } return arithmeticArray; } //get set方法 public int getRange() { return range; } public void setRange(int range) { this.range = range; } public int getMount() { return mount; } public void setMount(int mount) { this.mount = mount; } }

    逆波兰式的转换:

  • import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    
    public class NPR {
        //查重用字符串
        String CheckTheSame="";
        public String getFindTheSame() {
            return CheckTheSame;
        }
        public void setFindTheSame(String findTheSame) {
            this.CheckTheSame = findTheSame;
        }
        //判断ch是否为运算符
        public boolean inOp(char c){
            if (c == '(' || c == ')' || c == '+' || c == '-' || c == '*' || c == '÷'){
                return true;
            }
            else{
                return false;
            }
        }
        //判断ch是否为运算符
        public int precede(int op1,int op2){
            if (op1 == op2){
                return 0;
            }
            else if (op1 < op2){
                return -1;
            }
            else{
                return 1;
            }
        }
        //返回两个数的最大公约数(测试通过)
        public int greatestCommonDivisor(int m,int n) {
            int temp,i;
            int theDivisor=0;
            if(m<n) {
                temp = m;
                m = n;
                n = temp;
            }
            for(i=n;i>0;i--) {
                if((m%i==0)&&(n%i==0)) {
                    theDivisor=i;
                    break;
                }
            }
            return theDivisor;
        }
        //返回两个数的最小公倍数(测试通过)
        public int minTimes(int x,int y) {
            int temp=0;
            int theTimes=0;
            if(x<y) {
                temp = x;
                x = y;
                y = temp;
            }
            for(int i=x;i<=(x*y);i++) {
                if((i%x==0)&&(i%y==0)) {
                    theTimes=i;
                    break;
                }
            }
            return theTimes;
        }
        
        //数字化简
        public String simpleNum(int numerator,int denominator) {
            String theNumber = "";
            if(denominator==0) {
                System.exit(0);
            }
            if(numerator%denominator==0) {
                theNumber+=(numerator/denominator);
            }else {
                if(numerator<denominator) {
                    int maxFactor = greatestCommonDivisor(numerator,denominator);
                    if(maxFactor==0) {
                        theNumber+=0;
                    }else {
                        int tempNumerator = numerator/maxFactor;
                        int tempDenominator = denominator/maxFactor;
                        theNumber+=tempNumerator+"/"+tempDenominator;
                    }
                }else {
                    int theMod = numerator%denominator;
                    int theTimes = numerator/denominator;
                    int maxFactor = greatestCommonDivisor(theMod,denominator);
                    if(maxFactor==0) {
                        theNumber+=0;
                    }else {
                        theMod = theMod/maxFactor;
                        denominator = denominator/maxFactor;
                        theNumber+=theTimes+"\'"+theMod+"/"+denominator;
                    }
                }
            }
            return theNumber;
        }
        //逆波兰式
        public List exchangeNPR(String formula) {
            //用哈希键值对映射左运算符的优先级
            HashMap<String, Integer> lpri = new HashMap<String,Integer>();
            lpri.put("=",0);
            lpri.put("(",1);
            lpri.put("*",5);
            lpri.put("÷",5);
            lpri.put("+",3);
            lpri.put("-",3);
            lpri.put(")",6);
            //用哈希键值对映射右运算符的优先级
            HashMap<String, Integer> rpri = new HashMap<String,Integer>();
            rpri.put("=",0);
            rpri.put("(",6);
            rpri.put("*",4);
            rpri.put("÷",4);
            rpri.put("+",2);
            rpri.put("-",2);
            rpri.put(")",1);
            //创建栈
            Stack op = new Stack();
            op.data = new char[200];
            op.top=-1;
            op.top++;
            op.data[op.top]='=';
            //把传入的表达式转化成字符数组
            char[] exp = formula.toCharArray();
            //用来存储后缀表达式
            List postexp = new ArrayList(); 
            int j=0;
            while(j<exp.length) {
                if(!inOp(exp[j])) {
                    while(j<exp.length&&((exp[j]>='0'&& exp[j]<='9')||(exp[j]=='\'')||(exp[j]=='/'))) {
                        postexp.add(exp[j]);
                        j++;
                    }
                    postexp.add('#');
                }else {
                    switch(precede(lpri.get(op.data[op.top]+""),rpri.get(exp[j]+""))){
                    case -1:
                        op.top++;
                        op.data[op.top]=exp[j];
                        j++;
                        break;
                    case 0:
                        op.top--;
                        j++;
                        break;
                    case 1:
                        postexp.add(op.data[op.top]);
                        op.top--;
                        break;
                    }
                }    
            }
            while(op.data[op.top]!='=') {
                postexp.add(op.data[op.top]);
                op.top--;
            }
            return postexp;
        }
        //把运算数转换成数组{分子,分母}
        public int[] numberChangeArr(String number){
            int num[] = new int[2];
            if(number.indexOf('/')!=-1) {
                if(number.indexOf('\'')!=-1) {
                    int theTimes = Integer.parseInt(number.split("\'")[0]);
                    int numerator = Integer.parseInt((number.split("\'")[1]).split("/")[0]);
                    int denominator = Integer.parseInt((number.split("\'")[1]).split("/")[1]);
                    num[0] = theTimes*denominator+numerator;
                    num[1] = denominator;
                }else {
                    num[0] = Integer.parseInt(number.split("/")[0]);
                    num[1] = Integer.parseInt(number.split("/")[1]);
                }
            }else {
                num[0] = Integer.parseInt(number);
                num[1] = 1;
            }
            return num;
        }
        //后缀表达式的计算
        public String compvalue(String nprFormula) {
            Stack st = new Stack();
            st.top=-1;
            st.data2 = new String[200];
            int i=0;
            char[] postexp = nprFormula.toCharArray();
            while(i<postexp.length) {
                switch(postexp[i]) {
                case '+':
                    String a = st.data2[st.top];
                    st.top--;
                    String b = st.data2[st.top];
                    st.top--;
                    String c = "";
                    int numeratorA = numberChangeArr(a)[0];
                    int denominatorA = numberChangeArr(a)[1];
                    int numeratorB = numberChangeArr(b)[0];
                    int denominatorB = numberChangeArr(b)[1];
                    int theMinTimes = minTimes(denominatorA,denominatorB);
                    numeratorA=(theMinTimes/denominatorA)*numeratorA;
                    numeratorB=(theMinTimes/denominatorB)*numeratorB;
                    int theAdd = numeratorA+numeratorB;
                    c+=simpleNum(theAdd,theMinTimes);
                    st.top++;
                    st.data2[st.top]=c;
                    break;
                case '-':
                    String a2 = st.data2[st.top];
                    st.top--;
                    String b2 = st.data2[st.top];
                    st.top--;
                    String c2 = "";
                    int numeratorA2 = numberChangeArr(a2)[0];
                    int denominatorA2 = numberChangeArr(a2)[1];
                    int numeratorB2 = numberChangeArr(b2)[0];
                    int denominatorB2 = numberChangeArr(b2)[1];
                    int theMinTimes2 = minTimes(denominatorA2,denominatorB2);
                    int theReduct = 0;
                    theReduct = numeratorB2-numeratorA2;
                    numeratorA2=(theMinTimes2/denominatorA2)*numeratorA2;
                    numeratorB2=(theMinTimes2/denominatorB2)*numeratorB2;
                    theReduct = numeratorB2-numeratorA2;
                    if(theReduct==0) {
                        c2+="0";
                    }else if(theReduct>0) {
                        c2+=simpleNum(theReduct,theMinTimes2);
                    }else {
                        theReduct=Math.abs(theReduct);
                        c2+="-"+simpleNum(theReduct,theMinTimes2);
                    }
                    st.top++;
                    st.data2[st.top]=c2;
                    break;
                case '÷':
                    String a3 = st.data2[st.top];
                    st.top--;
                    String b3 = st.data2[st.top];
                    st.top--;
                    String c3 = "";
                    int numeratorA3 = numberChangeArr(a3)[0];
                    int denominatorA3 = numberChangeArr(a3)[1];
                    int numeratorB3 = numberChangeArr(b3)[0];
                    int denominatorB3 = numberChangeArr(b3)[1];
                    if(numeratorA3!=0) {
                        int theNumerator = numeratorB3*denominatorA3;
                        int theDenominator = denominatorB3*numeratorA3;
                        c3 += simpleNum(theNumerator,theDenominator);
                        st.top++;
                        st.data2[st.top]=c3;
                    }else {
                        System.exit(0);
                    }
                    break;
                case '*':
                    String a4 = st.data2[st.top];
                    st.top--;
                    String b4 = st.data2[st.top];
                    st.top--;
                    String c4 = "";
                    int numeratorA4 = numberChangeArr(a4)[0];
                    int denominatorA4 = numberChangeArr(a4)[1];
                    int numeratorB4 = numberChangeArr(b4)[0];
                    int denominatorB4 = numberChangeArr(b4)[1];
                    int numerator = numeratorA4*numeratorB4;
                    int denominator = denominatorA4*denominatorB4;
                    c4+=simpleNum(numerator,denominator);
                    st.top++;
                    st.data2[st.top]=c4;
                    break;
                default:
                    String d = "";
                    while((postexp[i]>='0'&&postexp[i]<='9')||(postexp[i]=='\'')||(postexp[i]=='/')) {
                        d+=postexp[i];
                        i++;
                    }
                    st.top++;
                    st.data2[st.top]=d;
                    break;
                }
                i++;
            }
            return st.data2[st.top];
        }
        
        
    
    }

     

  • e.测试运行
  •  

  1. 展示PSP
PSP2.1 Personal Software Process Stages Time Senior Student Time  
Planning 计划 8 8  
· Estimate 估计这个任务需要多少时间 8 9  
Development 开发 1 1  
· Analysis 需求分析 (包括学习新技术) 0.5 0.5  
· Design Spec 生成设计文档 0.2 0.2  
· Design Review 设计复审 1 2  
· Coding Standard 代码规范 0.1 0.15  
· Design 具体设计 0.5 0.5  
· Coding 具体编码 0.5 0.5  
· Code Review 代码复审 0.5 0.5  
· Test 测试(自我测试,修改代码,提交修改) 0.5 05  
Reporting 报告 0.1 0.1  
· 测试报告 0.1 0.1  
· 计算工作量 0.1 0.1  
· 并提出过程改进计划 0.1 0.1  
         
  1. 小结:

    这次做业收获很多,复习了一遍栈和树的知识,但我觉得这次最有价值的地方在于查重。但是思考的时间不多,所以这部分功能并未有完成。但我觉得随机生成的式子重复的概率极低,如果要去标记计算的话,那样要花费很多时间和内存,特别是题目的数量极多的情况下,甚至会出现内存溢出等错误,因此查重问题可以转变为如何构造不重复的表达式问题,由此我萌生了一种想法,就是为何不让式子在生成的时候,它就有限定规则,让他不可以重复生成呢。我发现在只有+、*的情况下,式子是逐渐变大的,那如果式子的操作数是由大到小递减组成的,自然就不会出现因为操作数交换顺序发生重复,对于减法的操作还没有想明白,也许可以限制特定位置的运算符来实现吧。

代码链接:https://git.coding.net/Secret_1943/Arithmetic.git

posted @ 2017-09-24 11:43  Secret_1943  阅读(445)  评论(2编辑  收藏  举报