结对编程(java实现),java并发编程
作者:谢伟洁3117004673
一、Github项目地址: https://github.com/jack-xie460/mytest.git
二、PSP表格
PSP2.1
|
Personal Software Process Stages
|
预估耗时(分钟)
|
实际耗时(分钟)
|
Planning
|
计划
|
|
|
· Estimate
|
· 估计这个任务需要多少时间
|
|
|
Development
|
开发
|
|
|
· Analysis
|
· 需求分析 (包括学习新技术)
|
|
|
· Design Spec
|
· 生成设计文档
|
|
|
· Design Review
|
· 设计复审 (和同事审核设计文档)
|
|
|
· Coding Standard
|
· 代码规范 (为目前的开发制定合适的规范)
|
|
|
· Design
|
· 具体设计
|
|
|
· Coding
|
· 具体编码
|
|
|
· Code Review
|
· 代码复审
|
|
|
· Test
|
· 测试(自我测试,修改代码,提交修改)
|
|
|
Reporting
|
报告
|
|
|
· Test Report
|
· 测试报告
|
|
|
· Size Measurement
|
· 计算工作量
|
|
|
· Postmortem & Process Improvement Plan
|
· 事后总结, 并提出过程改进计划
|
|
|
合计
|
|
|
|
三、效能分析
生成10000道50以内的题目耗时340ms
统计10000道题目的对错耗时119ms
速度还行!

四、实现过程
1.执行Produce类的start方法,程序开始运行,首先通过调用AmountOfNum类来判断输入指令是否正确,正确则返回题目数量,
通过调用BoundOfNum类来判断输入指令是否正确,正确则返回数值范围的最大值;
2.Produce类调用Expression类随机生成表达式,表达式又可通过子表达式和数值之间随机结合,而子表达式又可通过数值随机
结合,从而生成各种各样的表达式;
3.生成的表达式传入Calculate类,在Calculate中,通过调用houzhuiexp方法将传入的中缀表达式转化为后缀表达式,然后调用
calculate方法调用递归方法recusion对后缀表达式进行计算产生结果,;
4.将产生的题目和结果循环打印到相应的文件中;
5.执行Judge类来中的start方法进行对错统计,首先通过调用ExtractPath类来判断输入指令是否正确,正确则返回题目文档和
答案文档的路径,然后进行对错统计。
6.各个类之间的协同合作图:

五、代码说明
1.通过输入指令生成题目文档和答案文档的代码:

1 package jieduitest01;
2
3 import java.io.File;
4 import java.io.FileWriter;
5 import java.io.IOException;
6
7 //控制台输入命令,生成题目和答案放在对应文档中
8 public class Produce
9 {
10
11 public static void start()
throws IOException
12 {
13
14 File exerciseFile =
new File("E:\\java\\结对作业\\src\\jieduitest01\\Exercises.txt"
);
15 File answerFile =
new File("E:\\java\\结对作业\\src\\jieduitest01\\Answer.txt"
);
16 FileWriter writeToExercisefile =
new FileWriter(exerciseFile);
17 FileWriter writeToAnswerfile =
new FileWriter(answerFile);
18
19 System.out.println("请输入您想要生成的题目数量:(例如生成10道题目的格式:-n 10)"
);
20 while(!
AmountOfExp.method()) {}
21 int amount =
AmountOfExp.getAmount();
22
23 System.out.println("请输入您想要生成的题目中数值的范围:(例如数值在10以内格式:-r 10)"
);
24 while (!
BoundOfNum.method()) {}
25 int bound =
BoundOfNum.getBound();
26
27 String expression;
28 //可变数组存储后缀表达式用以查重
29 StringBuilder expressionSet =
new StringBuilder();
30 //循环打印题目和答案
31 for(
int i=0;i<amount;i++
)
32 {
33 expression =
Expression.expression(bound);
34 Calculate cal =
new Calculate(expression);
35 String houzhuiExp =
cal.houzhuiexp();
36
37 //产生的后缀表达式与之前的重复,即产生相同的题目
38 if(expression.indexOf(houzhuiExp)!=-1
)
39 {
40 i--
;
41 continue;
42 }
43
44 expressionSet.append(houzhuiExp);
45 String result =
cal.calculate();
46
47 //计算过程产生负数
48 if(result.equals("?"
))
49 {
50 i--
;
51 continue;
52 }
53
54 writeToExercisefile.write(i+1 +" 、" + expression + "="+"\n"
);
55 writeToAnswerfile.write(i+1 +"、" + result + "\n"
);
56
57 }
58 writeToExercisefile.close();
59 writeToAnswerfile.close();
60 }
61
62
63 }
View Code

1 package jieduitest01;
2
3 import java.util.Scanner;
4 import java.util.regex.Matcher;
5 import java.util.regex.Pattern;
6
7 //使用 -n 参数控制生成题目的个数
8 public class AmountOfExp
9 {
10
11 private static int amount;
12
13 public static int getAmount()
14 {
15 return amount;
16 }
17
18 //判断输入指令,并从正确输入指令中提取生成题目的数量
19 public static boolean method()
20 {
21
22 Pattern p = Pattern.compile("(-)(n)(\\s+)(\\d{1,})"
);
23 Scanner scan =
new Scanner(System.in);
24 String str =
scan.nextLine();
25 Matcher m =
p.matcher(str);
26 boolean bo =
m.matches();
27 String[] sarr ;
28 if(!
bo)
29 System.out.println("您输入的格式不合法,请按照格式重新输入,例如:-n 10"
);
30 else
31 {
32 sarr = str.split("\\s+"
);
33 amount = Integer.parseInt(sarr[1
]);
34 }
35 return bo;
36 }
37
38 }
View Code

1 package jieduitest01;
2
3 import java.util.Scanner;
4 import java.util.regex.Matcher;
5 import java.util.regex.Pattern;
6
7 //使用 -r 参数控制题目中数值范围
8 public class BoundOfNum
9 {
10
11 private static int bound;
12
13 public static int getBound()
14 {
15 return bound;
16 }
17
18 //判断输入指令,并从输入指令中提取题目中数值的范围
19 public static boolean method()
20 {
21
22 Pattern p = Pattern.compile("-r\\s+\\d+"
);
23 Scanner scan =
new Scanner(System.in);
24 String str =
scan.nextLine();
25 String[] sarr ;
26 Matcher m =
p.matcher(str);
27 boolean bo =
m.matches();
28 if(!
bo)
29 System.out.println("您输入的格式不合法,请按照格式重新输入,例如:-r 10"
);
30 else
31 {
32 sarr = str.split("\\s+"
);
33 bound = Integer.parseInt(sarr[1
]);
34 }
35 return bo;
36 }
37
38 }
View Code

1 package jieduitest01;
2
3 import java.util.Random;
4
5 //生成表达式
6 public class Expression
7 {
8
9 static Random ran=
new Random();
10
11 public static String expression(
int bound)
12 {
13
14 String ziexp1 =
null,ziexp2 =
null;
15
16 //概率结合不同的子表达式
17 int i = ran.nextInt(4
);
18 switch(i)
19 {
20
21 case 0
:
22 ziexp1 =
RandomNum.nextNumber(bound);
23 ziexp2 =
RandomNum.nextNumber(bound);
24 break;
25 case 1
:
26 ziexp1 =
RandomNum.nextNumber(bound);
27 ziexp2 =
SubExpression.ziepression(bound);
28 break;
29 case 2
:
30 ziexp1 =
SubExpression.ziepression(bound);
31 ziexp2 =
RandomNum.nextNumber(bound);
32 break;
33 case 3
:
34 ziexp1 =
SubExpression.ziepression(bound);
35 ziexp2 =
SubExpression.ziepression(bound);
36 break;
37 default :
38 }
39
40 String operater =
operater();
41 String exp = ziexp1 +" "+operater+" "+
ziexp2;
42 return exp;
43 }
44
45
46 public static String operater()
47 {
48
49 int opnum = ran.nextInt(4
);
50 switch(opnum)
51 {
52
53 case 0
:
54 return "+"
;
55 case 1
:
56 return "-"
;
57 case 2
:
58 return "×"
;
59 case 3
:
60 return "÷"
;
61 }
62 return null;
63 }
64
65 }
View Code
2.将生成的表达式计算出结果的代码(用到波兰表达式,即后缀表达式):

1 package jieduitest01;
2
3 import java.util.HashMap;
4 import java.util.Stack;
5
6 //传入生成的表达式计算出结果
7 public class Calculate
8 {
9 //用HashMap存储运算符及其优先级
10 HashMap<String,Integer>
opls;
11 String str0;
12
13 //构造函数,并初始化各个运算符的优先级
14 public Calculate(String str0)
15 {
16 this.str0 =
str0;
17 if(opls==
null)
18 {
19 opls =
new HashMap<String,Integer>(4
);
20 opls.put("+",0
);
21 opls.put("-",0
);
22 opls.put("×",1
);
23 opls.put("÷",1
);
24 }
25 }
26
27 //将中缀表达式转化成后缀表达式
28 public String houzhuiexp()
29 {
30 //出去空格符
31 String str = str0.replace(" ",""
);
32 //将中缀表达式分割放入数组
33 String[] strArray =
split(str);
34 //后缀表达式存储栈
35 Stack<String> houzhuiSta =
new Stack<String>
();
36 //临时栈
37 Stack<String> temStack =
new Stack<String>
();
38
39 for(String src:strArray)
40 {
41 //将操作数直接压入后缀表达式的栈
42 if(isNum(src))
43 houzhuiSta.push("("+src+")"
);
44 else //操作数或者括号
45 {
46 if(temStack.isEmpty()||src.equals("("
))
47 {
//"("或临时栈为空
48 temStack.push(src);
49 }
50 else
51 {
52 if(isLow(temStack.peek(),src))
53 {
54 if(!src.equals(")"
))
55 {
////优先级比临时栈栈首值的低
56 while((!temStack.isEmpty())&&
(isLow(temStack.peek(),src)))
57 {
58 houzhuiSta.push(temStack.pop());
59 }
60 temStack.push(src);
61 }
else//为")"
62 {
//临时栈栈首的值不为"("
63 while((!temStack.isEmpty())&&!(temStack.peek().equals("("
)))
64 {
65 houzhuiSta.push(temStack.pop());
66 }
67 //临时栈栈首的值为"("
68 if((!temStack.isEmpty())&&(temStack.peek().equals("("
)))
69 {
70 temStack.pop();
71 }
72 }
73 }
else
74 {
75 temStack.push(src);
76 }
77 }
78 }
79 }
80 //将临时栈的剩余值压入后缀栈
81 while(!
temStack.empty())
82 {
83 houzhuiSta.push(temStack.pop());
84 }
85 //将后缀栈中的后缀表达式转化为字符串返回
86 StringBuilder sb1 =
new StringBuilder();
87 for(String str1:houzhuiSta)
88 {
89 sb1.append(str1);
90 }
91 houzhuiSta.clear();
92 return sb1.toString();
93
94 }
95
96 //分割表达式
97 public String[] split(String str)
98 {
99
100 StringBuilder sb =
new StringBuilder(str.length()*2
);
101 for(
char ch:str.toCharArray())
102 {
103
104 if(ch=='+'||ch=='-'||ch=='×'||ch=='÷'||ch=='('||ch==')'
)
105 {
106 sb.append(","
);
107 sb.append(ch);
108 sb.append(","
);
109 }
110 else
111 {
112 sb.append(ch);
113 }
114 }
115 String src = sb.toString().replaceAll(",{2,}",","
);
116 return src.split(","
);
117
118 }
119
120 //分割后缀表达式
121 public String[] splitHou(String str)
122 {
123
124 StringBuilder sb =
new StringBuilder(str.length());
125 int i = 0
;
126 for(
char ch:str.toCharArray())
127 {
128 if(ch=='+'||ch=='-'||ch=='×'||ch=='÷'
)
129 {
130 sb.append(","
);
131 sb.append(ch);
132 }
133 else if(ch=='('||ch==')'
)
134 {
135 if(i>=1
)
136 {
137 sb.append(','
);
138 }
139 }
140 else
141 {
142 sb.append(ch);
143 i++
;
144 }
145 }
146 String src = sb.toString().replaceAll(",{2,}",","
);
147 return src.split(","
);
148
149 }
150
151 //化简分数
152 String simplify(String exResult)
153 {
154 SplitFra sp =
new SplitFra(exResult);
155 int numberater =
sp.getNumberater();
156 int deno =
sp.getDeno();
157 int comDiv =
comDivisor(numberater,deno);
158 numberater /=
comDiv;
159 deno /=
comDiv;
160 int integer = numberater/
deno;
161 int fration = numberater%
deno;
162 if(integer == 0
)
163 {
164 return fration + "/" +
deno;
165 }
else if (fration == 0
)
166 {
167 return integer+""
;
168 }
else
169 {
170 return integer + "'" + fration + "/" +
deno;
171 }
172 }
173
174 //辗转相除法求最大公约数
175 int comDivisor(
int a,
int b)
176 {
int c = 1
;
177 while(a % b != 0
)
178 {
179 c = a %
b;
180 a =
b;
181 b =
c;
182 }
183 return b;
184 }
185
186 //判断是否是操作数
187 public boolean isNum(String str)
188 {
189 for (
char ch : str.toCharArray())
190 {
191 if(ch=='+'||ch=='-'||ch=='×'||ch=='÷'||ch=='('||ch==')'
)
192 return false;
193 }
194 return true;
195 }
196
197 //比较优先级
198 public boolean isLow(String pop, String str)
199 {
200 if(str.equals(")"
))
201 return true;
202 if(opls.get(pop)==
null||opls.get(str)==
null)
203 return false;
204 return opls.get(pop)>=
opls.get(str);
205 }
206
207 //调用递归方法利用后缀表达式计算结果
208 public String calculate()
209 {
210 //后缀表达式
211 String houhzhuiExp =
houzhuiexp();
212 String[] strs =
splitHou(houzhuiexp());
213 //调用递归得到结果
214 String exResult =
recursion(strs);
215 //计算过程产生负数返回"?"
216 if(exResult.equals("?"
))
217 {
218 return "?"
;
219 }
220 String result ;
221 //结果是分数,化简
222 if(exResult.contains("/"
))
223 {
224 result =
simplify(exResult);
225 }
else
226 {
227 result =
exResult;
228 }
229 return result;
230 }
231 //递归方法
232 public String recursion(String[] str)
233 {
234 //计算过程是否出现负数的标记
235 boolean flag =
false;
236 int nowlength =
str.length;
237 if(str[str.length-1]==" "
)
238 {
239 nowlength = str.length-1
;
240 }
else if(str.length == 1)
//后缀表达式长度为1则递归结束返回结果
241 {
242 return str[0
];
243 }
244 String[] nextstr =
new String[nowlength-2
];
245 for(
int i = 2;i<nowlength;i++
)
246 {
247
248 if(str[i].equals("+")||str[i].equals("-")||str[i].equals("×")||str[i].equals("÷"
))
249 {
250 String num1 = str[i-2
];
251 String num2 = str[i-1
];
252 String operater =
str[i];
253 String result;
254 switch(operater)
255 {
256 case "+"
:
257 result =
Math.add(num1,num2);
258 break;
259 case "-"
:
260 result =
Math.sub(num1,num2);
261 //有负数产生
262 if(result.equals("?"
))
263 {
264 flag =
true;
265 }
266 break;
267 case "×"
:
268 result =
Math.mul(num1,num2);
269 break;
270 case "÷"
:
271 result =
Math.div(num1,num2);
272 break;
273 default :
274 result =
null;
275 }
276 //后缀表达式每计算一次,就构建新的后缀表达式
277 for(
int i1=0;i1<nowlength-2;i1++
)
278 {
279 if(i1<i-2
)
280 {
281 nextstr[i1] =
str[i1];
282 }
else if(i1==i-2
)
283 {
284 nextstr[i1] =
result;
285 }
else
286 {
287 nextstr[i1] = str[i1+2
];
288 }
289 }
290 break;
291 }
292 }
293 if(flag)
294 {
295 return "?"
;
296 }
297 return recursion(nextstr);
298 }
299
300 }
View Code
3.针对相应的题目文档,对答案文档的进行对错统计的代码:

1 package jieduitest01;
2
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.FileNotFoundException;
6 import java.io.FileReader;
7 import java.io.FileWriter;
8 import java.io.IOException;
9
10 /*
11 * 输入指令将题目文件的计算结果与答案文件的答案比较
12 * 将正确的及错误的题目数量和题号打印到Grade.txt文件中
13 */
14 public class Judge
15 {
16
17 public static void start()
throws IOException
18 {
19 System.out.println("请输入您的操作指令来进行答案的对错统计:(格式:-e <exercisefile>.txt -a <answerfile>.txt)"
);
20 while(!
ExtractPath.method()) {}
21 String exeFilePath =
ExtractPath.getExeFilePath();
22 String answerFilePath =
ExtractPath.getAnswerFilePath();
23 BufferedReader exe =
new BufferedReader(
new FileReader(exeFilePath));
24 BufferedReader answer =
new BufferedReader(
new FileReader(answerFilePath));
25 File grade =
new File("E:\\java\\结对作业\\src\\jieduitest01\\Grade.txt"
);
26 FileWriter writeToGrade =
new FileWriter(grade);
27
28 String exep = ""
;
29 StringBuilder corretNum =
new StringBuilder();
30 StringBuilder wrongNum =
new StringBuilder();
31 int corret = 0
;
32 int wrong = 0
;
33 int num = 1
;
34 while((exep = exe.readLine())!=
null)
35 {
36 String anstr =
answer.readLine();
37 String[] exestrs = exep.split("、"
);
38 String[] anstrs = anstr.split("、"
);
39 String str = exestrs[1].replaceAll("=", ""
);
40 Calculate cal =
new Calculate(str);
41 String result =
cal.calculate();
42 String answerstr = anstrs[1
];
43 if(result.equals(answerstr))
44 {
45 corret++
;
46 corretNum.append(num + ","
);
47 }
else
48 {
49 wrong++
;
50 wrongNum.append(num + ","
);
51 }
52 num++
;
53
54 }
55 writeToGrade.write("Corret: "+corret+"("+corretNum.toString()+")"+"\n"
);
56 writeToGrade.write("Wrong: "+wrong+"("+wrongNum.toString()+")"
);
57 writeToGrade.close();
58 exe.close();
59 answer.close();
60 }
61 }
View Code

1 package jieduitest01;
2
3 import java.io.File;
4 import java.util.Scanner;
5 import java.util.regex.Matcher;
6 import java.util.regex.Pattern;
7
8 /*
9 * 判断输入指令是否正确,并从正确指令中提取目标文件位置
10 * 题目文件位置可由getExeFilePath方法获得
11 * 答案文件位置可由getAnswerFilePath方法获得
12 */
13 public class ExtractPath {
14
15 private static String exeFilePath;
16 private static String answerFilePath;
17
18 public static String getExeFilePath()
19 {
20 return exeFilePath;
21 }
22
23 public static String getAnswerFilePath()
24 {
25 return answerFilePath;
26 }
27
28 public static boolean method()
29 {
30
31 Pattern p = Pattern.compile("(-)(e)(\\s+)(\\S+)(\\.)(txt)(\\s+)(-)(a)(\\s+)(\\S+)(\\.)(txt)"
);
32 Scanner scan =
new Scanner(System.in);
33 String str =
scan.nextLine();
34 Matcher m =
p.matcher(str);
35 boolean bo =
m.matches();
36 String[] sarr;
37 if(!
bo)
38 {
39 System.out.println("您输入的格式不合法,请按照格式重新输入,格式:-e <exercisefile>.txt -a <answerfile>.txt)"
);
40 }
else
41 {
42 sarr = str.split("\\s+"
);
43 exeFilePath = sarr[1
];
44 answerFilePath = sarr[3
];
45 File src1 =
new File(exeFilePath);
46 File src2 =
new File(answerFilePath);
47 if(!(src1.exists()&&
src2.exists()))
48 {
49 System.out.println("您输入的文件夹我找不到啊!!!还请重新输入"
);
50 bo =
false;
51 }
52 }
53 return bo;
54 }
55
56 }
View Code
六、测试运行
1.生成10000道100以内题目、答案和对错统计:



2.生成500道50以内的题目、答案和对错统计:


3.修改答案文档中的前11道题并单独执行对错统计:



七、项目小结
通过这次作业我体验到了编程的乐趣,学习了很多新的知识,收获很多。
用户点评