结对作业
结对编程
这个作业属于哪个课程 | 课程 |
---|---|
这个作业要求在哪里 | 要求 |
这个作业的目标 | 四则运算生成器+生成应用程序+结对 |
成员名称 | 陆梦龙(我自己) |
代码链接
我的代码
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 120 |
Estimate | 估计这个任务需要多少时间 | 10 | 0 |
Development | 开发 | 960 | 960 |
Analysis | 需求分析 (包括学习新技术) | 120 | 120 |
Design Spec | 生成设计文档 | 60 | 240 |
Design Review | 设计复审 | 10 | 10 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 20 | 30 |
Design | 具体设计 | 60 | 240 |
Coding | 具体编码 | 960 | 1080 |
Code Review | 代码复审 | 10 | 20 |
Test | 测试(自我测试,修改代码,提交修改) | 5 | 10 |
Reporting | 报告 | 60 | 180 |
Test Repor | 测试报告 | 60 | 30 |
Size Measurement | 计算工作量 | 10 | 10 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 10 | 10 |
合计 | 425 | 700 |
程序实现
构造特殊数据结构
构造分数数据结构
建立数据类
public class Value
实现内容的存储
int natural; int fraction; int denominator;
定义三个数来实现对自身数值的定义
实现格式的转换
public void reduce(){
System.out.println("进行化简");
while(fraction<0){
fraction+=denominator;
natural--;
}
if(fraction>=denominator&&fraction!=0&&denominator!=0)
{
natural+=fraction/denominator;
fraction%=denominator;
}
if(fraction!=0&&fraction!=1&&denominator!=0&&denominator!=1&&denominator%fraction==0){
int gcd=Get_Gcd(denominator,fraction);
denominator/=gcd;
fraction/=gcd;
}
}
public void refraction(){
fraction+=natural*denominator;
natural=0;
System.out.println("该Value转化为分数"+fraction+'\\'+denominator);
}
构造两个方法,以此来实现分数的转化和化简
分数化简
- 将所有整数与分母相乘,转换为分数
- 判断若是分数大于分母,则向整数进位
- 如果有最大公约数,则让它们被最大公约数共除
完成了分数化简
分数转化
- 将整数部分全部与分母相乘加到分数上
- 将整数部分置零
完成了数字完全转化为分数
实现数字的加减乘除
public static Value Add(Value v1,Value v2) throws CloneNotSupportedException {
System.out.println("进行加法运算");
Value v1_clone=v1.clone();
Value v2_clone=v2.clone();
v1_clone.refraction();
v2_clone.refraction();
int f=v1_clone.fraction*v2_clone.denominator+v1_clone.denominator*v2_clone.fraction;
int d=v1_clone.denominator* v2_clone.denominator;
Value v3=new Value(0,f,d);
System.out.println("计算出了新的结果"+f+'\\'+d);
v3.reduce();
return v3;
}
public static Value Sub(Value v1,Value v2) throws CloneNotSupportedException {
System.out.println("进行减法运算");
Value v1_clone=v1.clone();
Value v2_clone=v2.clone();
v1_clone.refraction();
v2_clone.refraction();
int f= v1_clone.fraction* v2_clone.denominator-v1_clone.denominator*v2_clone.fraction;
int d=v1_clone.denominator* v2_clone.denominator;
Value v3=new Value(0,f,d);
System.out.println("计算出了新的结果"+f+'\\'+d);
v3.reduce();
return v3;
}
public static Value Mut(Value v1,Value v2) throws CloneNotSupportedException {
System.out.println("进行乘法运算");
Value v1_clone=v1.clone();
Value v2_clone=v2.clone();
v1_clone.refraction();
v2_clone.refraction();
int f=v1_clone.fraction*v2_clone.fraction;
int d=v1_clone.denominator*v2_clone.denominator;
Value v3=new Value(0,f,d);
System.out.println("计算出了新的结果"+f+'\\'+d);
v3.reduce();
return v3;
}
public static Value Div(Value v1,Value v2) throws CloneNotSupportedException {
System.out.println("进行除法运算");
Value v1_clone=v1.clone();
Value v2_clone=v2.clone();
v1_clone.refraction();
v2_clone.refraction();
int f=v1_clone.fraction*v2_clone.denominator;
int d=v1_clone.denominator*v2_clone.fraction;
Value v3=new Value(0,f,d);
System.out.println("计算出了新的结果"+f+'\\'+d);
v3.reduce();
return v3;
}
构造四个方法,实现加减乘除
加法实现
- 将数字全部转化为分数
- 彼此的分子与彼此的分母相乘然后两两相加作为新的分子,分母相乘作为新的分母
- 将得到的新的数化简返回
减法实现
- 将数字全部转化为分数
- 彼此的分子与彼此的分母相乘然后两两相减作为新的分子,分母相乘作为新的分母
- 将得到的新的数化简返回
乘法实现
- 将数字全部转化为分数
- 彼此的分子相乘作为新的分子,分母相乘作为新的分母
- 将得到的新的数化简返回
除法实现
- 将数字全部转化为分数
- 彼此的分子与彼此的分母相乘分别作为新的分子分母
- 将得到的新的数化简返回
实现字符串的输出
public String toString() {
String str="";
reduce();
if(natural!=0)
{
str+=String.valueOf(natural);
}
if(natural!=0&&fraction!=0)
{
str+='\'';
}
if(fraction!=0)
{
str=str+String.valueOf(fraction)+'/'+String.valueOf(denominator);
}
if(natural==0&&fraction==0)
{
str+='0';
}
return str;
}
- 检测整数部分,若是有不为0的整数,则将其添加到字符串里
- 检测整数与分数部分,若是整数不为0且有分数部分存在,则加上’
- 检测分数部分,加上分数部分
- 若是两部分都为0,则返回0
实现数据到字符串的表达
获取一个随机的数
public static Value Get_Random_Value(int Range){
if(random.nextBoolean()){
int na=1+random.nextInt(Range-1);
System.out.println("随机生成自然数"+String.valueOf(na));
return new Value(na);
}
else{
int den=2+random.nextInt(Range-2);
int fra=1+random.nextInt(den-1);
System.out.println("随机生成真分数"+fra+'\\'+String.valueOf(den));
return new Value(0,fra,den);
}
}
- 得到取值的范围
- 判断此次生成的数是自然数还是分数
- 若是生成的是自然数,则随机一个Value,向整数部分填入随机的整数,分数部分为0.若是生成的是分数,则随机一个Value,向分数部分填入随机的数
- 返回新的Value
得到数据的double
public double toDouble(){
double d;
d=natural+(double)fraction/denominator;
return d;
}
构造表达式数据结构
建立数据类
public class Expression
实现内容的存储
public static char[] operators_char={'+', '-', '÷', '×'};
Value[] values;
ArrayList<Integer> operate;
实现表达式的求值
public Value toValue() throws CloneNotSupportedException {
System.out.println("为"+toString()+"进行表达式值计算");
Value value=values[0];
for(int i=0;i<operate.size();i++)
{
if(operators_char[operate.get(i)]=='+'){value=Value.Add(value,values[i+1]);}
else if(operators_char[operate.get(i)]=='-'){value=Value.Sub(value,values[i+1]);}
else if(operators_char[operate.get(i)]=='×'){value=Value.Mut(value,values[i+1]);}
else if(operators_char[operate.get(i)]=='÷'){value=Value.Div(value,values[i+1]);}
}
return value;
}
- 首先的到一个Value
- 然后依照每一个储存的符号和储存的Value,调用Value类中的加减乘除的方法来对其进行一一计算。
- 将最后的得到的Value返回
因此得到了表达式的Value值
将表达式转化为字符串
public String toString() {
String str=values[0].toString();
for(int i=0;i<operate.size();i++)
{
str+=operators_char[operate.get(i)];
str+=values[i+1].toString();
}
return str;
}
public String toFromalString(){
String str=values[0].toString();
str+=operators_char[operate.get(0)];
str+=values[1].toString();
for(int i=1;i<operate.size();i++)
{
if((operators_char[operate.get(i-1)]=='+'||operators_char[operate.get(i-1)]=='-')&&(operators_char[operate.get(i)]=='÷'||operators_char[operate.get(i)]=='×'))
str="("+str+")";
str+=operators_char[operate.get(i)];
str+=values[i+1].toString();
}
return str;
}
构造两个方法,一个用来返回不标准的字符串,一个用来返回标准的字符串
-
返回不标准的字符串
-
先将储存的第一个Value化为字符串
-
然后加上符号然后在加上随后的Value字符串形式,然后如果还有下一个符号,就再对下一个符号和Value做同样的事,以此类推
-
返回的到的字符串
-
返回标准的字符串
-
先将储存的第一个Value化为字符串
-
然后加上符号然后在加上随后的Value字符串形式,然后如果还有下一个符号,就再对下一个符号和Value做同样的事,如果下一个符号的优先度比前面的符号优先度高,则对前面的字符串用()包裹
-
返回的到的字符串
随机生成表达式
public static Expression Get_Random_Expression(int range) throws CloneNotSupportedException {
int i=1+random.nextInt(max_operators);
ArrayList<Integer> o=new ArrayList<Integer>();
Value v[]=new Value[i+1];
v[0]=Value.Get_Random_Value(range);
for(int j=0;j<i;j++){
for(;;)
{
o.add(random.nextInt(3));
System.out.println("为表达式添加符号"+operators_char[o.get(j)]);
v[j + 1] = Value.Get_Random_Value(range);
Expression e=new Expression(v,o);
System.out.println("进行表达式生成检测");
if(e.toValue().toDouble()>=0){System.out.println("合格,表达式计算大于0");break;}
else
{
System.out.println("不合格,表达式计算小于0");
o.remove(o.size()-1);
System.out.println("删除最后一位操作符");
}
}
}
System.out.println("生成表达式成功");
return new Expression(v,o);
}
- 先随机生成一个数决定计算符数量
- 生成随机的Value储存
- 然后生成计算符和随后的Value,对现有的表达式求值,如果值小于0就重新更换生成的计算符和Value在求,直到通过
- 重复以上步骤直到生成了指定数量的计算符
- 返回表达式
将表达式加入到哈希表中
public void AddedDictionary()
{
ArrayList<Integer> list=GetSortedIntegerList(operate);
if(expression_dictionary.get(list)==null)
{
ArrayList<Expression> List=new ArrayList<Expression>();
List.add(this);
expression_dictionary.put(list,List);
}
else
{
ArrayList<Expression> List=(ArrayList<Expression>)expression_dictionary.get(list);
List.add(this);
}
}
- 将操作符数组进行自然排序作为键值
- 查看哈希表有无对应键值下的表达式列表,若没有,则生成对应的表
- 将表达式加入对应键值下的表达式列表
检查两个表达式是否相同
public static boolean CheckExpressionSame(Expression e1,Expression e2){
if(e1.operate.size()!=e2.operate.size())return false;
ArrayList<String[]> temp1=new ArrayList<String[]>();
ArrayList<String[]> temp2=new ArrayList<String[]>();
for(int i=0;i<e1.operate.size();i++){
if(operators_char[e1.operate.get(i)]=='+'||operators_char[e1.operate.get(i)]=='×')
{
temp1.add(GetRLStringExpression(e1,i));
temp2.add(GetRLStringExpression(e2,i));
}
}
return CheckListHaveSmall(temp1,temp2);
}
检查两者的操作符数组大小是否相同,若不同,返回假
重复数组大小的下列行为
如果符号为可以左右互换而不影响结果的符号的话,获取表达式当前指定位置运算符的的左右字符串,检查是否真的相同如果相同,返回真
如果都不同,返回假
获取表达式指定位置运算符的左右的字符串
public static String[] GetRLStringExpression(Expression e,int x){
String strR=e.values[0].toString();
for(int i=0;i<x;i++)
{
strR+=operators_char[e.operate.get(i)];
strR+=e.values[i+1].toString();
}
String strL=e.values[x+1].toString();
for(int i=x+1;i<e.operate.size();i++)
{
strL+=operators_char[e.operate.get(i)];
strL+=e.values[i+1].toString();
}
String[] s={strR,strL};
return s;
}
检查两串字符串数组列表是否有相同的地方
public static boolean CheckListHaveSmall(ArrayList<String[]> a1,ArrayList<String[]> a2){
boolean flag=false;
for(String[] s1:a1)
for(String[] s2:a2)
{
if(s1[0]==s2[0]&&s1[1]==s2[1])return true;
if(s1[0]==s2[1]&&s1[1]==s2[0])return true;
}
return false;
}
构造主函数
返回一个文件的输出流
public static FileWriter fileWriter_writer(String s) throws IOException {
File f = new File(s);
if(!f.exists()){
f.mkdir();
}
FileWriter fr = new FileWriter(f);
return fr;
}
实现生成指定数量的问题和对应的答案(最关键!!!!)
public static void Main(int Problem_of_number,int Range_of_number) throws CloneNotSupportedException, IOException {
int problem_of_number=Problem_of_number;
int range_of_number=Range_of_number;
File directory = new File("");
String exercise_file=directory.getAbsolutePath()+"\\Exercises.txt";
FileWriter exercise_file_writer=fileWriter_writer(exercise_file);
String answer_file=directory.getAbsolutePath()+"\\Answers.txt";
FileWriter answer_file_writer=fileWriter_writer(answer_file);
for(int i=0;i<problem_of_number;i++)
{
System.out.println("开始生成第"+String.valueOf(i+1)+"个表达式");
for(;;)
{
Expression e = Expression.Get_Random_Expression(range_of_number);
boolean flag=true;
ArrayList<Expression> List=(ArrayList<Expression>)Expression.expression_dictionary.get(Expression.GetSortedIntegerList(e.operate));
if(List!=null){
for(Expression expression:List){
for(int j=0;j<expression.operate.size();j++)
{
if(Expression.CheckExpressionSame(e,expression)==true)flag=false;
}
}
}
if(flag==true)
{
e.AddedDictionary();
System.out.println("开始写入文件");
exercise_file_writer.write(e.toFromalString()+"\n");
answer_file_writer.write(e.toValue().toString()+"\n");
break;
}
}
}
exercise_file_writer.close();
answer_file_writer.close();
}
- 得到当前目录并创建输出流
- 进行循环,循环要生成问题的数量次
- 生成表达式,查找是否在哈希表中有与其相等的表达式,若有,重新生成,没有。则添加到相关的哈希表中,并且将表达式的答案和正确形式输入分别输入到两个文件中
图形化界面的实现
public static void main(String[] args) throws IOException, CloneNotSupportedException {
JFrame f = new JFrame("四则运算生成器");
f.setSize(600, 200);
f.setLocation(580, 200);
f.setLayout(new FlowLayout());
JLabel lName = new JLabel("输入生成问题的数量:");
// 输入框
JTextField tfName = new JTextField("");
tfName.setText("");
tfName.setPreferredSize(new Dimension(80, 30));
JLabel lPassword = new JLabel("输入数的范围:");
// 输入框
JTextField tfPassword = new JTextField("");
tfPassword.setText("");
tfPassword.setPreferredSize(new Dimension(80, 30));
JButton b = new JButton("开始生成");
b.setPreferredSize(new Dimension(100, 30));
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int Problem_of_number;
int Range_of_number;
Problem_of_number=Integer.valueOf(tfName.getText());
Range_of_number=Integer.valueOf(tfPassword.getText());
try {
Main(Problem_of_number,Range_of_number);
} catch (CloneNotSupportedException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
f.add(lName);
f.add(tfName);
f.add(lPassword);
f.add(tfPassword);
f.add(b);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
tfPassword.grabFocus();
}
实现图形化界面
按下按钮调用Main函数生成文件
测试结果
性能测试
我没有钱啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊,JPoritle过期了啊啊啊😭