软工第三次作业
小组成员
3123004287肖锦瑞
3123004268黄泽鹏
Github 仓库链接
这个作业属于哪个课程 | 软件工程 |
---|---|
这个作业要求在哪里作业要求 | 作业要求 |
这个作业的目标 | 实现一个自动生成小学四则运算题目的命令行程序 |
PSP 表格
Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|
计划 | 15 | 20 |
估计这个任务需要多少开发时间 | 10 | 15 |
开发 | 600 | 700 |
需求分析(包括学习新技术) | 60 | 65 |
生成设计文档 | 20 | 25 |
设计复审 | 30 | 35 |
代码规范(为目前的开发制定合适的规范) | 20 | 25 |
具体设计 | 30 | 35 |
具体编码 | 60 | 60 |
代码复审 | 20 | 25 |
测试(自我测试,修改代码,提交代码) | 30 | 60 |
报告 | 30 | 35 |
测试报告 | 20 | 25 |
计算工作量 | 10 | 15 |
事后总结 | 15 | 20 |
合计 | 700 | 830 |
计算模块接口的设计与实现过程
计算结果的核心思想
利用栈数据结构,先进后出原则
方法:用两个栈(一个用于保存运算符,一个用于保存操作数),其中的运算符包括:+,-,*,/,(,),
表达式有括号、运算符、和操作数(数字)组成。我们根据以下4种情况从左到右逐个将这些实体送入栈处理
1,将操作数压入操作数栈
2,将运算符压入运算符栈
3,忽略左括号
4,在遇到右括号时,弹出一个运算符,弹出所需数量的操作数,并将运算符和操作数的运算结果压入操作数栈
最后:
在处理完最后一个右括号的时候,操作数栈中只会又一个值,他就是表达式的值
程序流程图
各模块具体实现代码
计算模块
public class Calculation {//设置运算符的优先级public static Map<String, Integer> map = new HashMap<String, Integer>() {/*** */private static final long serialVersionUID = 3684443232637633564L;{put("(", 0);put("+", 1);put("-", 1);put("×", 2);put("÷", 2);put(")", 3);put("=", 4);}};//将最终结果进行格式化public static String finalResult(String num) throws Exception {String[] nums = new String[2];int mole, deno;nums = FractionCalculation.change(num);mole = Integer.parseInt(nums[0]);deno = Integer.parseInt(nums[1]);String finalResult = FormatProcess.Format(mole, deno);if(finalResult.contains("-")) {//部分运算结果为负数throw new Exception();}else {return finalResult;}}// 括号内运算符的优先级是从低到高public static void doCalcul(Stack<String> operaStack, Stack<String> numStack, boolean flag) throws Exception {//将两个数值及运算符出栈进行计算String nowOpera = operaStack.pop();String nowNum_2 = numStack.pop();String nowNum_1 = numStack.pop();String result = FractionCalculation.result(nowOpera, nowNum_1, nowNum_2); if(result.contains("-")) { //结果为负 throw new Exception();}else {numStack.push(result); }if(flag) {if("(".equals(operaStack.peek())) {//栈顶为(operaStack.pop();}else {doCalcul(operaStack, numStack, flag);//栈顶不为“(”}}else {if(!operaStack.empty()) { doCalcul(operaStack, numStack, flag);}}}// 优先级比较public static void comparePriority(Stack<String> operaStack, Stack<String> numStack, String operator) throws Exception{String topOpera = operaStack.peek();int priority = map.get(operator) - map.get(topOpera);//优先级判断if (priority > 0) {operaStack.push(operator);} else {String nowOpera = operaStack.pop();String nowNum_2 = numStack.pop();String nowNum_1 = numStack.pop();String result = FractionCalculation.result(nowOpera, nowNum_1, nowNum_2);numStack.push(result);if (operaStack.empty()) {//运算符栈为空operaStack.push(operator);} else {comparePriority(operaStack, numStack, operator);}}}
}
题目生成模块
//生成题目及计算出答案
public class GenerateItem {public static void createitem(int range, int num) {String operator[] = { "+", "-", "×", "÷" };String allAnswer = ""; //全部答案String allItems = ""; //全部题目for(int i = 0;i < num;i++) {int operatornum = (int) (Math.random() * 3 + 1);String figure = null, operate = null;int undo = 0;int bracketnum = 0;String expression = "";boolean flag = true;String result;Stack<String> operaStack = new Stack<String>();Stack<String> numStack = new Stack<String>();try {// 未包含最后一个数while (operatornum > 0) {int tag = (int) (Math.random() * 2); //用于判断是否要生成括号figure = FormatProcess.fraction(range);operate = operator[(int) (Math.random() * 4)];if (tag == 0 && bracketnum < operatornum - 1) {expression += "(";operaStack.push("(");bracketnum++;undo++;flag = false;} else if (tag == 1&& flag == true && undo > 0) {expression += figure + ")" + " " + operate + " ";numStack.push(figure);Calculation.doCalcul(operaStack, numStack, true);Calculation.comparePriority(operaStack, numStack, operate);operatornum--;undo--;flag = false;} else { expression += figure + " " + operate + " ";if (operaStack.empty()) {operaStack.push(operate);numStack.push(figure);} else {numStack.push(figure);Calculation.comparePriority(operaStack, numStack, operate);}operatornum--;flag = true;}}// 添加最后一个数if (undo == 0) {figure = FormatProcess.fraction(range);expression += figure;} else if (undo == 1) {if (expression.startsWith("((") || expression.startsWith("(") && expression.contains(")") == false) {figure = FormatProcess.fraction(range);expression = expression.substring(1) + figure;} else {figure = FormatProcess.fraction(range);expression += figure + ")";}} else if (undo == 2) {if (expression.startsWith("((")) {figure = FormatProcess.fraction(range);expression = expression.substring(2) + figure;} else if (expression.startsWith("(")) {figure = FormatProcess.fraction(range);expression = expression.substring(1) + figure + ")";} else {figure = FormatProcess.fraction(range);expression += figure + "))";}}numStack.push(figure);Calculation.doCalcul(operaStack, numStack, false);result = Calculation.finalResult(numStack.peek());expression += " " + "=";if(expression.contains("÷ 0")) {i--;expression = "";}else {allItems += (i + 1) + "、 " + expression + "\n" ;allAnswer += (i + 1) + "、 " + result + "\n" ;}} catch (Exception e) {// TODO: handle exceptioni--;}}FileOutPut.FileOutPut(allItems, 1);FileOutPut.FileOutPut(allAnswer, 2);}
}
分数计算模块
public class FractionCalculation {public static String result(String nowOpera, String nowNum_1, String nowNum_2){String result = null;int mole_1, deno_1, mole_2, deno_2;String[] value_1 = change(nowNum_1); mole_1 = Integer.parseInt(value_1[0]);deno_1 = Integer.parseInt(value_1[1]);String[] value_2 = change(nowNum_2);mole_2 = Integer.parseInt(value_2[0]);deno_2 = Integer.parseInt(value_2[1]);int flag = 0;if(nowOpera=="+") flag=1;else if(nowOpera=="-") flag=2;else if(nowOpera=="×") flag=3;else if(nowOpera=="÷") flag=4;switch (flag) {case 1:result = add(mole_1, deno_1, mole_2, deno_2);break;case 2:result = subtraction(mole_1, deno_1, mole_2, deno_2);break;case 3:result = multiplication(mole_1, deno_1, mole_2, deno_2);break;case 4:result = division(mole_1, deno_1, mole_2, deno_2);break;default:break;} return result; } //加法public static String add(int a, int b, int c, int d) {int mole, deno;mole = a * d + c * b;deno = b * d; return mole + "/" + deno;}//减法public static String subtraction(int a, int b, int c, int d){int mole, deno;mole = a * d - c * b;deno = b * d;return mole + "/" + deno;}//乘法public static String multiplication(int a, int b, int c, int d) {int mole, deno;mole = a * c;deno = b * d;return mole + "/" + deno;}//除法public static String division(int a, int b, int c, int d) {int mole, deno;mole = a * d;deno = b * c;return mole + "/" + deno;}//将分数转换成a/b形式并将a、b添加进array数组中public static String[] change(String num){String [] array = new String [2];if(num.contains("/")) {if(num.contains("'")) {//带分数String[] tarray = num.split("/|'");int[] sarray = new int[3];for(int i = 0;i<3;i++) {sarray[i] = Integer.parseInt(tarray[i]);} array[0] = String.valueOf(sarray[0] * sarray[2] + sarray[1]);array[1] = String.valueOf(sarray[2]); }else { array = num.split("/"); }}else {array[0] = num;array[1] = "1";}return array;}
}
格式处理模块
//格式处理
public class FormatProcess {public static String fraction(int range) {int mole, deno;mole = (int) (Math.random() * range);deno = (int) (Math.random() * range + 1);return Format(mole, deno);}public static String Format(int mole, int deno) {String fraction = null;int min = 0;min = (mole > deno) ? deno : mole;if (mole == 0) {fraction = "0";} else if (mole % deno == 0) {fraction = String.valueOf(mole / deno);} else {for (int i = min; i >= 2; i--) {if (mole % i == 0 && deno % i == 0) {mole = mole / i;deno = deno / i;}}if (mole > deno) {fraction = String.valueOf(mole / deno) + "'" + String.valueOf(mole % deno) + "/" + String.valueOf(deno);} else {fraction = mole + "/" + deno;}}return fraction;}
}
文件输出保存模块
public class FileOutPut {public static void FileOutPut(String str, int tag) {String path = "";if(tag == 1) {path = "D:\\Exercises.txt";}else if(tag == 2){path = "D:\\Answers.txt";}File file = new File(path);FileWriter fw;try {fw = new FileWriter(file,false);fw.write(str);fw.close();System.out.println("文件保存成功!");} catch (IOException e) {// TODO Auto-generated catch blockSystem.out.println("文件保存不成功!");}}}
main方法
public class PairPro {public static void main(String[] args) {// TODO Auto-generated method stubint i=args.length;int num,range;long startTime = 0,endTime = 0;if(i==4) {//从命令行接收四个参数 -n,num,-r,rangeif(args[0]=="-n"&&args[2]=="-r") {//生成题目if(isNumeric(args[1])==true&&isNumeric(args[3])==true) {num=Integer.valueOf(args[1]);range=Integer.valueOf(args[3]);if(num>0&&range>0) {startTime = System.currentTimeMillis();GenerateItem.createitem(range, num);endTime = System.currentTimeMillis();}else {System.out.println("您输入的参数不合法!!!");System.exit(0);}}}else {System.out.println("您输入的参数不合法!!!");System.exit(0);}}else{System.out.println("您输入的参数数目不符合要求");System.exit(0);}System.out.println("程序运行时间:" + (endTime - startTime) + "ms");}//正则纯数字判断public static boolean isNumeric(String str) {Pattern pattern = Pattern.compile("[0-9]*");Matcher isNum = pattern.matcher(str);if (!isNum.matches()) {return false;}return true;}}
运行结果
代码优化
·加入检查题目是否重复的模块
·加入答案检查模块
性能分析
cpu性能分析
字符和字符串型数据占用大量资源
个人总结
肖锦瑞
优点:二人结对编程情况下会比较认真负责,遇到不懂就一起在网上找资料一起学习
缺点:代码风格不同,组合代码时效率较差
黄泽鹏
优点:两个合作,想法更丰富,多元,计划制定更完善,资料查找更全面,工作量降低,能互相学习对方的写代码优点,专注自己擅长的部分,弱势部分由队友补足。
不足:没有建立良好的沟通渠道,沟通成本较高,没有建立良好统一的代码规范,后期管理会比较麻烦。