结对作业

结对编程

这个作业属于哪个课程 课程
这个作业要求在哪里 要求
这个作业的目标 四则运算生成器+生成应用程序+结对
成员名称 陆梦龙(我自己)

代码链接
我的代码

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);

   }

构造两个方法,以此来实现分数的转化和化简
分数化简

  1. 将所有整数与分母相乘,转换为分数
  2. 判断若是分数大于分母,则向整数进位
  3. 如果有最大公约数,则让它们被最大公约数共除
    完成了分数化简

分数转化

  1. 将整数部分全部与分母相乘加到分数上
  2. 将整数部分置零
    完成了数字完全转化为分数

实现数字的加减乘除

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;
    }

构造四个方法,实现加减乘除

加法实现

  1. 将数字全部转化为分数
  2. 彼此的分子与彼此的分母相乘然后两两相加作为新的分子,分母相乘作为新的分母
  3. 将得到的新的数化简返回

减法实现

  1. 将数字全部转化为分数
  2. 彼此的分子与彼此的分母相乘然后两两相减作为新的分子,分母相乘作为新的分母
  3. 将得到的新的数化简返回

乘法实现

  1. 将数字全部转化为分数
  2. 彼此的分子相乘作为新的分子,分母相乘作为新的分母
  3. 将得到的新的数化简返回

除法实现

  1. 将数字全部转化为分数
  2. 彼此的分子与彼此的分母相乘分别作为新的分子分母
  3. 将得到的新的数化简返回

实现字符串的输出

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;
    }
  1. 检测整数部分,若是有不为0的整数,则将其添加到字符串里
  2. 检测整数与分数部分,若是整数不为0且有分数部分存在,则加上’
  3. 检测分数部分,加上分数部分
  4. 若是两部分都为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);
        }
    }
  1. 得到取值的范围
  2. 判断此次生成的数是自然数还是分数
  3. 若是生成的是自然数,则随机一个Value,向整数部分填入随机的整数,分数部分为0.若是生成的是分数,则随机一个Value,向分数部分填入随机的数
  4. 返回新的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;
    }
  1. 首先的到一个Value
  2. 然后依照每一个储存的符号和储存的Value,调用Value类中的加减乘除的方法来对其进行一一计算。
  3. 将最后的得到的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;
    }

构造两个方法,一个用来返回不标准的字符串,一个用来返回标准的字符串

  1. 返回不标准的字符串

  2. 先将储存的第一个Value化为字符串

  3. 然后加上符号然后在加上随后的Value字符串形式,然后如果还有下一个符号,就再对下一个符号和Value做同样的事,以此类推

  4. 返回的到的字符串

  5. 返回标准的字符串

  6. 先将储存的第一个Value化为字符串

  7. 然后加上符号然后在加上随后的Value字符串形式,然后如果还有下一个符号,就再对下一个符号和Value做同样的事,如果下一个符号的优先度比前面的符号优先度高,则对前面的字符串用()包裹

  8. 返回的到的字符串

随机生成表达式

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);
    }
  1. 先随机生成一个数决定计算符数量
  2. 生成随机的Value储存
  3. 然后生成计算符和随后的Value,对现有的表达式求值,如果值小于0就重新更换生成的计算符和Value在求,直到通过
  4. 重复以上步骤直到生成了指定数量的计算符
  5. 返回表达式

将表达式加入到哈希表中

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);
        }
    }
  1. 将操作符数组进行自然排序作为键值
  2. 查看哈希表有无对应键值下的表达式列表,若没有,则生成对应的表
  3. 将表达式加入对应键值下的表达式列表

检查两个表达式是否相同

    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();
    }
  1. 得到当前目录并创建输出流
  2. 进行循环,循环要生成问题的数量次
  3. 生成表达式,查找是否在哈希表中有与其相等的表达式,若有,重新生成,没有。则添加到相关的哈希表中,并且将表达式的答案和正确形式输入分别输入到两个文件中

图形化界面的实现

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过期了啊啊啊😭

posted @ 2021-10-25 23:53  陆梦龙  阅读(26)  评论(0编辑  收藏  举报