软件工程概论个人作业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)此实验中有关结果的诸多方面未考虑完全,比如正确率、或者是错题集等等,需要利用下一周的时间进行最后的修改、完善。
三、项目计划日志
四、时间记录日志
五、缺陷记录日志