软工第三次作业-结对项目
软工第三次作业
小组成员
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 exception
i--;
}
}
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 block
System.out.println("文件保存不成功!");
}
}
}
main方法
public class PairPro {
public static void main(String[] args) {
// TODO Auto-generated method stub
int i=args.length;
int num,range;
long startTime = 0,endTime = 0;
if(i==4) {//从命令行接收四个参数 -n,num,-r,range
if(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性能分析

字符和字符串型数据占用大量资源

个人总结
肖锦瑞
优点:二人结对编程情况下会比较认真负责,遇到不懂就一起在网上找资料一起学习
缺点:代码风格不同,组合代码时效率较差
黄泽鹏
优点:两个合作,想法更丰富,多元,计划制定更完善,资料查找更全面,工作量降低,能互相学习对方的写代码优点,专注自己擅长的部分,弱势部分由队友补足。
不足:没有建立良好的沟通渠道,沟通成本较高,没有建立良好统一的代码规范,后期管理会比较麻烦。

浙公网安备 33010602011771号