软件工程概论个人作业02

这周的四则运算项目要求增多:主要有以下几个方面

编程思路:

1.随着老板所列出的要求的增多,必须将控制参数的实现都封装在函数中,以便程序的理解和规范性。

2.根据出题的难度,随机数确定运算式包含的参数个数,随机数确定符号,参数个数比运算符号多一个,生成题目;

3.将题目传给栈,由栈计算结果,并返回结果;

4.用随机数确定加减的运算数,根据随机数确定加减法还是乘除法(2个运算符还是4个运算符),比对输入的结果,若有余数则输入余数(以字符串形式保存);

5.设计分数类,其中包括分数的加减乘除以及输出形式的函数。(真分数,先产生分母,之后产生0-分母数值的分子);

6.括号的实现,设运算式长度为n,则可建立一个长度为n的数组名为KuoHao[],记录每个元素周围的括号情况,0为无括号,正数为左括号,负数为右括号。则可以产生的括号的长度(即括号包围的运算数的个数)为2 ~ (n-1),利用for循环控制括号的长度,循环变量 i 为2 ~ (n - 1),循环体是另一个循环,循环变量 j 为0 ~ (n - i + 1) (即可以加左括号的运算数的位置),如果括号添加正确,其相对应值相加为0,否则添加不正确。

 代码:

package hh;

import java.util.Random;
import java.util.Scanner;
import java.util.Stack;

//分数类
class fraction {
    public int fenMu,fenZi;

    public int getFenMu() {
        return fenMu;
    }

    public void setFenMu(int fenMu) {
        this.fenMu = fenMu;
    }

    public int getFenZi() {
        return fenZi;
    }

    public void setFenZi(int fenZi) {
        this.fenZi = fenZi;
    }

    public fraction(int fenMu, int fenZi) {
        this.fenMu = fenMu;
        this.fenZi = fenZi;
        yueFen();
    }
    
    public fraction(){}
    
  //找出两数的最大公约数
    public int MaxCommon(int a,int b){
    	//保证第一个参数大于第二个参数
        if(a<b)
        {
            int temp;
            temp=a;
            a=b;
            b=temp;
        }
        while(a%b!=0)   //在余数不为零时循环
        {
            int temp=a%b;
            a=b;
            b=temp;
        }
        return b;  //返回最大公约数
    }
    
    //找出两数的最小公倍数
    public int MinCommon(int a,int b){
    	return a*b/MaxCommon(a,b);
    }
    
    //约分化简
    public void yueFen(){
        int y = 1;
        for(int i = fenZi;i > 1;i--){
            if(fenZi % i == 0 && fenMu % i == 0){
                y = i;
                break;
            }
        }
            fenZi /= y;
            fenMu /= y;
        
    }
    
    //计算(加)
    public fraction add(fraction b){
    	fraction c = null;
        int newFenZi = this.fenZi * b.getFenMu() + this.fenMu * b.getFenMu();
        int newFenMu = this.fenMu * b.getFenMu();
        c = new fraction(newFenMu,newFenZi);
        return c;
    }
    
    //计算(减)
    public fraction subtract(fraction b){
    	fraction c = null;
        int newFenZi = this.fenZi * b.getFenMu() - this.fenMu * b.getFenZi();
        int newFenMu = this.fenMu * b.getFenMu();
        c = new fraction(newFenMu,newFenZi);
        return c;
    }
    
    //计算(乘)
    public fraction multiply(fraction b){
    	fraction c = null;
        int newFenZi = this.fenZi * b.getFenZi();
        int newFenMu = this.fenMu * b.getFenMu();
        c = new fraction(newFenMu,newFenZi);
        return c;
    }
    
    //计算(除)
    public fraction divide(fraction b){
    	fraction c = null;
        int newFenZi = this.fenZi * b.getFenMu();
        int newFenMu = this.fenMu * b.getFenZi();
        c = new fraction(newFenMu,newFenZi);
        return c;
    }
    
    //输出分数形式
    public String toString(){
        if(fenZi != 0){
            return fenZi + "/" + fenMu;
        }
        return "0";
    }
    
}

public class kk {
	public static String[] Answer=new String[100];
	//生成整数计算式添加限制条件,type为运算式类型  0代表整数式,1代表真分数式
    public static String[] createYunSuanShi(int hasChengChu,int hasKuoHao,int hasFuShu,int hasYuShu,int minNum,int maxNum,int n,int type) {
        int i = 0;
        int z = 0;
        String yunSuanShiTemp;
        String[] yunSuanShiArray = new String[n];
        int operatorScope = 2 + 2 * hasChengChu;//运算符范围,2或4,2代表只有加减,4代表有加减乘除
        int length;
        String[] operatorArray = {"+","-","*","/"};
        String[] operatorNum = null;//存储运算数
        int num_index;//运算数下标
        String[] operatorSymbol = null;//存储运算符
        int symbol_index;//运算符下标
        int[] brackets = null;//存储括号个数
        
        while(i < n) {
            length = Integer.parseInt(getOperatorNumber(0, 0,9)) + 2;//计算式运算数长度
            operatorNum = new String[length];
            operatorSymbol = new String[length - 1];
            num_index = 0;
            symbol_index = 0;
            operatorNum[num_index++] = getOperatorNumber(type,minNum, maxNum);//随机生成操作数
            for(int j = 0;j < length - 1;j++){
                operatorSymbol[symbol_index++] = operatorArray[Integer.parseInt(getOperatorNumber(0,0,operatorScope-1))];//随机生成操作符
                operatorNum[num_index++] = getOperatorNumber(type, minNum,maxNum);//随机生成操作数
            }        
            if(hasKuoHao == 1){
                brackets = randomAddBracket(length);//生成括号数组
            }
            //构造运算式
            yunSuanShiTemp = "";
            for(int j = 0;j < length;j++){
                //添加左括号
                if(hasKuoHao == 1){
                    for(int k = 0;k < brackets[j];k++){
                        yunSuanShiTemp += "(";
                    }
                }
                yunSuanShiTemp += " " + operatorNum[j] + " ";//加上运算数
                
                //添加右括号
                if(hasKuoHao == 1){
                    for(int k = 0;k > brackets[j];k--){
                        yunSuanShiTemp += ")";
                    }
                }
                //如果不是最后一个运算数则要加上运算符
                if(j != length - 1){
                    yunSuanShiTemp += operatorSymbol[j];
                }
            }
            
            //计算结果
            String answer = expressCalculate(yunSuanShiTemp, hasFuShu, hasYuShu, type, length - 1);
            if((answer.equals("ERROR"))){
                continue;
            }
            yunSuanShiTemp += "=" /*+ answer*/;
            Answer[z]=answer;
            z++;
            //检验重复
            boolean chongFu = false;
            for(int j = 0;j < i;j++){
                if((yunSuanShiArray[j].equals(yunSuanShiTemp))){
                    chongFu = true;
                    break;
                }
            }
            if(chongFu == false){
                yunSuanShiArray[i++] = yunSuanShiTemp;
            }
        }
        return yunSuanShiArray;
    }
    
    //表达式计算,参数为字符串类型的运算式
    public static String expressCalculate(String express,int hasFuShu,int hasYuShu,int type,int symbolNum){
        Stack<String> num = new Stack<String>();
        Stack<String> symbolS = new Stack<String>();
        symbolS.push("#");
        express += "#";
        char ch;
        int i = 0;
        int s = 0;
        ch = express.charAt(i);
        while(s < symbolNum){
            if(ch == ' '){//读到空格,说明开始读运算数
                String readNumStr = "";
                while(true){
                    ch = express.charAt(++i);
                    if(ch == ' '){
                        break;
                    }
                    readNumStr += ch;
                    
                }
                if((i + 1) < express.length()){
                    ch = express.charAt(++i);
                }
                num.push(readNumStr);
            }else{//读到的是运算符
                char compare = priorityCompare(symbolS.peek(),ch + "");
                
                if(compare == '='){//如果是右括号
                    symbolS.pop();
                    ch = express.charAt(++i);
                }else if(compare == '>'){//ch的优先级小于栈顶的优先级     比栈顶的优先级高就不算,入栈,低就弹栈运算
                    //弹出两个运算数,弹出一个运算符
                    String bStr = num.pop();
                    String aStr = num.pop();
                    String symbolT = symbolS.pop();
                    String c = yunSuan(aStr,bStr,symbolT,hasFuShu,hasYuShu,type);
                    if(c.equals("ERROR")){
                        return "ERROR";
                    }else if(c.indexOf("余") >= 0 && s != symbolNum - 1){//有余数
                        return "ERROR";
                    }else{
                        num.push(c);
                    }
                    s++;
                }else{
                    symbolS.push(ch + "");
                    if((i + 1) < express.length()){
                        ch = express.charAt(++i);
                    }
                }
            
            }
        }
        return num.pop();
    }
    
    public static String yunSuan(String aStr,String bStr,String symbol,int hasFuShu,int hasYuShu,int type){
        if(type == 0){//整数
            int a = Integer.parseInt(aStr);
            int b = Integer.parseInt(bStr);
            if(symbol.equals("+")){
                return "" + (a + b);
            }else if(symbol.equals("-")){
                if(a - b < 0 && hasFuShu == 0){
                    return "ERROR";
                }else{
                    return "" + (a - b);
                }
            }else if(symbol.equals("*")){
                return "" + (a * b);
            }else{
                if(b == 0){
                    return "ERROR";
                }
                if(a % b == 0){
                    return "" + (a / b);
                }else{
                    if(hasYuShu == 1){
                        return (a / b) + "余" + (a % b);
                    }else{
                        return "ERROR";
                    }
                }
            }
        }else{//分数
            String[] af = aStr.split("/");
            String[] bf = bStr.split("/");
            if(af[0].equals("0") || bf[0].equals("0")){
                return "ERROR";
            }
            fraction a = new fraction(Integer.parseInt(af[1]),Integer.parseInt(af[0]));
            fraction b = new fraction(Integer.parseInt(bf[1]),Integer.parseInt(bf[0]));
            if(symbol.equals("+")){
                return a.add(b).toString();
            }else if(symbol.equals("-")){
            	fraction c = a.subtract(b);
                if(hasFuShu == 1 && c.getFenZi() < 0){
                    return "ERROR";
                }
                return c.toString();
            }else if(symbol.equals("*")){
                return a.multiply(b).toString();
            }else{
                return a.divide(b).toString();
            }
        }
    }    

    //判断优先级
    public static char priorityCompare(String a,String b){
        char[][] priority = {
                {'>','>','<','<','<','>','>'},
                {'>','>','<','<','<','>','>'},
                {'>','>','>','>','<','>','>'},
                {'>','>','>','>','<','>','>'},
                {'<','<','<','<','<','=','>'},
                {'>','>','>','>',' ','>','>'},
                {'<','<','<','<','<',' ','='}
        };
        int a_index = index_symbol(a);
        int b_index = index_symbol(b);
        return priority[a_index][b_index];
    }
    
    public static int index_symbol(String a){
        String p = "+-*/()#";
        return p.indexOf(a);
    }
    
    //随机生成括号,参数为运算式的运算数的个数
    public static int[] randomAddBracket(int length){
        int[] brackets = new int[length];
        for(int i = 0;i < brackets.length;i++)   brackets[i] = 0;
        Random rd = new Random();
        for(int i = 2;i < length;i++){//添加的括号长度(括号包围的运算数的个数)
            for(int j = 0;j < length - i + 1;j++){
                int t = rd.nextInt(2);//随机生成0或1,0代表不加括号,1代表加括号
                if(t == 1){
                    if(brackets[j] >= 0 && brackets[j + i - 1] <= 0){//要加的括号的第一个运算数周围没有右括号,且 最后一个运算数周围没有左括号
                        int counteract = 0;
                        for(int k = j;k < j + i;k++){//将要加的括号之间的所有运算数对应的brackets相加,
                                                        //如果和为0说明这个括号之间的括号是匹配的,不会出现括号交叉现象
                            counteract += brackets[k];
                        }
                        if(counteract == 0){
                            brackets[j]++;
                            brackets[j + i - 1]--;
                        }
                    }
                }
            }
        }
        return brackets;
    }
    
    //随机生成一个运算数(                type==0代表生成整数,type==1代表生成真分数,maxNum代表数值范围 0-(maxNum-1)               )
    public static String getOperatorNumber(int type,int minNum,int maxNum){
        Random rd = new Random();
        int a;
        while(true){
            a = rd.nextInt(maxNum-minNum)+minNum;
            if(type == 0){//随机生成一个整数
                return "" + a;
            }else{//随机生成一个真分数
                if(a == 0){
                    continue;
                }
                int b = rd.nextInt(a-minNum)+minNum;
                fraction c = new fraction(a,b);
                return c.toString();
            }
        }
    }
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner sc = new Scanner(System.in);
		System.out.print("请输入所要生成题目的数目:");
	    int n = sc.nextInt();
        System.out.print("请输入: 0、整数式 ; 1、分数式:");
        int type = sc.nextInt();
        System.out.print("是否有乘除法?(1有,0没有):");
        int hasChengChu = sc.nextInt();
        System.out.print("是否有括号?(1有,0没有):");
        int hasKuoHao = sc.nextInt();
        System.out.print("加减有无负数?(1有,0没有):");
        int hasFuShu = sc.nextInt();
        System.out.print("除法有无余数?(1有,0没有):");
        int hasYuShu = sc.nextInt();
        System.out.print("数值范围(最小数):");
        int minNum = sc.nextInt();
        System.out.print("数值范围(最大数):");
        int maxNum = sc.nextInt();
        String[] yunSuanShiArray = createYunSuanShi(hasChengChu, hasKuoHao, hasFuShu, hasYuShu,minNum, maxNum, n, type);
        for(int i = 0;i < yunSuanShiArray.length;i++){
            System.out.print(yunSuanShiArray[i]);
            String result=sc.next();
            if(result.equals(Answer[i])){
            	System.out.print(" 回答正确!");
            }
            else{
            	System.out.print(" 回答错误!"+"正确答案为:"+Answer[i]);
            }
            System.out.println();
        }
        sc.close();
	}
}

  结果截图:

编程总结:

1)程序虽然可以实现初步的需求出题,算题,并对结果进行判断,但还有很多地方需要改善,比如代码的重复,以及数值范围的规范性;

2)其中编程过程中也是汲取了一些其他同学的想法,希望以后自己可以独立思考,完成任务;

3)此实验中有关结果的诸多方面未考虑完全,比如正确率、或者是错题集等等,需要利用下一周的时间进行最后的修改、完善。

 

三、项目计划日志

 

 

四、时间记录日志

 

 

五、缺陷记录日志

 

 

posted @ 2017-03-10 12:53  蘑菇蘑菇终于开花了  阅读(168)  评论(0编辑  收藏  举报