zoukankan      html  css  js  c++  java
  • 四则运算

    一 . 项目介绍

    项目成员:黄梓垲  蔡海杰

    项目仓库:github

    二. PSP表格

    PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
    Planning 计划 20   40
    · Estimate 估计这个任务需要多少时间 10 10
    Development 开发 20 30     
    · Analysis 需求分析 (包括学习新技术) 30 30
    · Design Spec · 生成设计文档 20 40
    · Design Review · 设计复审 (和同事审核设计文档) 10 10
    · Coding Standard · 代码规范 (为目前的开发制定合适的规范) 20 20
    · Design · 具体设计 20 40
    · Coding · 具体编码 400 600
    · Code Review · 代码复审 10 30
    · Test · 测试(自我测试,修改代码,提交修改) 30 30
    Reporting 报告 30 40
    · Test Report · 测试报告 20 30
    · Size Measurement · 计算工作量 20 20
    · Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 20 20
    合计   680 990

     

    三. 项目功能

      由界面输入参数,实现了题目的生成以及去重,问题与答案的文件保存,用户输入答案文件与标准答案的校对以及结果文件生成

      运行示例(Answerfile.txt为用户提交文件):

      

    四. 项目分析与代码设计

      1. 由于题目设计真分数运算,所以采用分数作为基本的运算单位。使用ExpressionResult类保存每条表达式以及它的运算结果

    复制代码
    public class Fraction {
        //分子
        private Integer numerator;
        //分母
        private Integer denominator;
    
        //取最大公因数化简
        public Fraction(Integer n, Integer d) {
            Integer GCD = Calculator.GCD(n, d);
            this.numerator = n /= GCD;
            this.denominator = d /= GCD;
        }
    
    
        //重写toString方法,以真分数形式表示
        @Override
        public String toString() {
            if (this.numerator > this.denominator && this.denominator != 1 && this.getNumerator() > 0 && this.getDenominator() > 0) {
                int num = numerator / denominator;
                return num + "'" + numerator % denominator + "/" + denominator;
            } else if (denominator == 1) {
                return numerator.toString();
            } else return numerator + "/" + denominator;
        }
    }
    复制代码

      

    复制代码
    public class ExpressionResult {
    
        private String expression;
        private String result;
    
        @Override
        public String toString() {
            return expression+"="+result;
        }
    }
    复制代码

      2. 很多人采用二叉树生成表达式或者中缀转后缀表达式的思路,我则是直接进行表达式的生成与计算,在生成表达式时采用HashSet无法重复的特性来存放表达式达到去重的目的

    复制代码
    //表达式的生成,采用HashSet存放表达式,直接去重,可以免去后续检测是否重复
        public static HashSet<ExpressionResult> generateExpression(Integer r, Integer n) {
            HashSet<ExpressionResult> expressionResultHashSet = new HashSet<>();
            for (int i = 0; i < r; i++) {
                //生成第一个操作符和操作数,在后面计算中使用firstNum存放计算的结果
                char firstOps = GeneratorUtil.getOperator();
                Fraction firstNum = GeneratorUtil.getFraction(n);
                char secondOps = firstOps;
                Fraction secondNum = firstNum;
                ExpressionResult expressionResult = new ExpressionResult();
                StringBuilder expression = new StringBuilder().append(firstNum);
                //生成后续两个操作符并进行表达式的拼接
                for (int j = 0; j < 2; j++) {
                    //获取第二个操作数
                    secondNum = GeneratorUtil.getFraction(n);
                    switch (secondOps) {
                        //加法则直接进行拼接,不需要额外操作
                        case '+':
                            //将当前运算符保存,后面在优先级比较中会使用到(下同)
                            firstOps = secondOps;
                            expression.append(secondOps).append(secondNum);
                            //保存运算的中间结果(下同)
                            firstNum = Calculator.ADD(firstNum, secondNum);
                            //获取下一个操作符(下同)
                            secondOps = GeneratorUtil.getOperator();
                            break;
                        case '-':
                            firstOps = secondOps;
                            //由于不能产生负数,所以在减法时要进行比较,如果前数小于后数则将表达式倒置拼接
                            if (Calculator.CMP(firstNum, secondNum)) {
                                firstNum = Calculator.SUB(firstNum, secondNum);
                                expression.append(secondOps).append(secondNum);
                            } else {
                                expression = new StringBuilder().append(secondNum).append(secondOps).append(expression);
                                firstNum = Calculator.SUB(secondNum, firstNum);
                            }
                            secondOps = GeneratorUtil.getOperator();
                            break;
                        case '×':
                            //乘法优先级大,在这里判断前面是否有优先级较小的加减操作,有的话将表达式带上括号再拼接乘法运算
                            if (firstOps == '+' || firstOps == '-') {
                                expression = new StringBuilder().append("(").append(expression).append(")").append(secondOps).append(secondNum);
                            } else {
                                expression.append(secondOps).append(secondNum);
                            }
                            //保存运算结果
                            firstNum = Calculator.MUL(firstNum, secondNum);
                            firstOps = secondOps;
                            secondOps = GeneratorUtil.getOperator();
                            break;
                        case '÷':
                            //除法优先级大,在这里判断前面是否有优先级较小的加减操作,有的话将表达式带上括号再拼接乘法运算
                            if (firstOps == '+' || firstOps == '-') {
                                expression = new StringBuilder().append("(").append(expression).append(")").append(secondOps).append(secondNum);
                                firstNum = Calculator.DIV(secondNum, firstNum);
                            } else {
                                expression.append(secondOps).append(secondNum);
                                firstNum = Calculator.DIV(firstNum, secondNum);
                            }
                            firstOps = secondOps;
                            secondOps = GeneratorUtil.getOperator();
                            break;
                    }
                }
                //将表达式和结果保存,放进HashSet
                expressionResult.setExpression(expression.toString());
                expressionResult.setResult(firstNum.toString());
                expressionResultHashSet.add(expressionResult);
            }
            return expressionResultHashSet;
        }
    复制代码

      3. 随机数和操作符的获取

    复制代码
    public class GeneratorUtil {
    
        private static final char OPERATORS[] = {'+', '-', '×', '÷'};
        private static final Random R = new Random();
    
        public static Fraction getFraction(int maximum) {
            //调整随机数为整数或者分数
            boolean isFraction = R.nextBoolean();
            return isFraction ? new Fraction(R.nextInt(maximum) + 1, R.nextInt(maximum) + 1) : new Fraction(R.nextInt(maximum) + 1, 1);
        }
    
        public static char getOperator() {
            return OPERATORS[R.nextInt(4)];
        }
    
    }
    复制代码

      4. 分数的运算操作

    复制代码
    public class Calculator {
    
        /**
         * 化简
         */
        public static Integer simplify(Integer numerator, Integer denominator) {
            if (denominator == 0) return numerator;
            return numerator % denominator == 0 ? denominator : simplify(denominator, numerator % denominator);
        }
    
        //相加
        public static Fraction ADD(Fraction first, Fraction second) {
            return new Fraction(first.getNumerator() * second.getDenominator() + first.getDenominator() * second.getNumerator(),
            first.getDenominator() * second.getDenominator());
        }
    
        //相减
        public static Fraction SUB(Fraction first, Fraction second) {
            return new Fraction(first.getNumerator() * second.getDenominator() - first.getDenominator() * second.getNumerator(), first.getDenominator() * second.getDenominator());
        }
    
        //相乘
        public static Fraction MUL(Fraction first, Fraction second) {
            return new Fraction(first.getNumerator() * second.getNumerator(), first.getDenominator() * second.getDenominator());
        }
    
        //相除
        public static Fraction DIV(Fraction first, Fraction second) {
            return MUL(first, Countdown(second));
        }
        //取倒
        public static Fraction Countdown(Fraction fraction) {
            return new Fraction(fraction.getDenominator(), fraction.getNumerator());
        }
    
        //比较大小
        public static boolean CMP(Fraction first, Fraction second) {
            Fraction result = DIV(first, second);
            return result.getNumerator() > result.getDenominator() && result.getNumerator() > 0 ? true : false;
        }
        //获取最大公因数并约去(辗转相除法)
        public static int GCD(int a, int b) {
            if (b == 0) return a;
            return a % b == 0 ? b : GCD(b, a % b);
        }
    }
    复制代码

      5. 题目、答案文件和答案比对结果文件的生成

    复制代码
    public static void generateFile(HashSet<ExpressionResult> expressionResultHashSet) throws IOException {
            File questionFile = new File("Exercises.txt");
            File answerFile = new File("Answers.txt");
            if (!questionFile.exists()) {
                questionFile.createNewFile();
            }
            if (!answerFile.createNewFile()) {
                answerFile.createNewFile();
            }
            try (BufferedWriter abw = new BufferedWriter(new FileWriter(answerFile));
                 BufferedWriter qbw = new BufferedWriter(new FileWriter(questionFile))) {
    
                int count = 1;
                for (ExpressionResult e : expressionResultHashSet) {
                    try {
                        qbw.write(count + "." + e.getExpression());
                        qbw.newLine();
                        abw.write(count + "." + e.getResult());
                        abw.newLine();
                //将表达式放入队列,在监听线程中拼接到界面中去
                        GuiForOperator.queue.add(count + "." + e.getExpression() + "=" + e.getResult());
                        count++;
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }
    
            }
        }
    复制代码
    复制代码
    public static void CompareAnswers(File answerFile) throws IOException {
            List<String> correctList = new ArrayList<>();
            List<String> wrongList = new ArrayList<>();
            try (BufferedReader qrAnswer = new BufferedReader(new FileReader(answerFile));
                 BufferedReader qrExercise = new BufferedReader(new FileReader("Answers.txt"))) {
                String eStr = null;
                String aStr = null;
                while ((eStr = qrExercise.readLine()) != null && (aStr = qrAnswer.readLine()) != null) {
                    String orderNum = eStr.substring(0, eStr.indexOf("."));
                    String standardAnswer = aStr.substring(2, aStr.length());
                    String submitAnswer = eStr.substring(2, eStr.length());
                    if (standardAnswer.equals(submitAnswer)) {
                        correctList.add(orderNum);
                    } else {
                        wrongList.add(orderNum);
                    }
                }
            }
            File gradeFile = new File("Grade.txt");
            if (!gradeFile.exists()) {
                gradeFile.createNewFile();
            }
            try (BufferedWriter bw = new BufferedWriter(new FileWriter(gradeFile))) {
                StringBuilder correctStr = new StringBuilder().append("Correct: ").append(correctList.size()).append(" (");
                StringBuilder wrongStr = new StringBuilder().append("Wrong: ").append(wrongList.size()).append(" (");
                correctList.forEach((e) -> {
                    correctStr.append(e + ",");
                });
                wrongList.forEach((e) -> {
                    wrongStr.append(e + ",");
                });
                bw.write(correctStr.toString().substring(0, correctStr.lastIndexOf(",")) + ")");
                bw.newLine();
                if (wrongList.size() != 0) {
                    bw.write(wrongStr.toString().substring(0, wrongStr.lastIndexOf(",")) + ")");
                } else {
                    bw.write(wrongStr.append(")").toString());
                }
           //将比对结果放入队列,在监听线程中拼接到界面中去
                GuiForOperator.queue.add(correctStr.toString().substring(0, correctStr.lastIndexOf(",")) + ")");
                GuiForOperator.queue.add(wrongStr.toString().substring(0, wrongStr.lastIndexOf(",")) + ")");
    
            }
        }
    复制代码

      6. 界面:包括传入参数、文件以及结果显示

    复制代码
    public class GuiForOperator extends JFrame {
       // 使用队列存放表达式,起线程监听,有则取出并显示
        public static BlockingQueue<String> queue = new LinkedBlockingQueue<>();
    
        private JPanel contentPane;
        private JTextField textField;
        private JTextField textField_1;
        public JTextArea textArea;
        public JScrollPane scrollPane;
    
    
        /**
         * Create the frame.
         */
        public GuiForOperator() {
            setTitle("u56DBu5219u8FD0u7B97");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setBounds(100, 100, 706, 495);
            contentPane = new JPanel();
            contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
            setContentPane(contentPane);
            contentPane.setLayout(null);
    
            JLabel label = new JLabel("u9898u76EEu6570u91CFuFF1A");
            label.setBounds(55, 43, 76, 18);
            contentPane.add(label);
    
            textField = new JTextField();
            textField.setBounds(163, 35, 282, 35);
            contentPane.add(textField);
            textField.setColumns(10);
    
            JLabel label_1 = new JLabel("u6700u5927u968Fu673Au6570uFF1A");
            label_1.setBounds(55, 91, 125, 18);
            contentPane.add(label_1);
    
            textField_1 = new JTextField();
            textField_1.setBounds(163, 83, 282, 35);
            contentPane.add(textField_1);
            textField_1.setColumns(10);
    
    
            scrollPane = new JScrollPane(textArea);
            textArea = new JTextArea();
            textArea.setEditable(false);
            textArea.setBounds(55, 167, 591, 255);
            textArea.setLineWrap(true);
            scrollPane.setBounds(55, 167, 591, 255);
            scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
            contentPane.add(scrollPane);
            scrollPane.setViewportView(textArea);
    
    
            JButton button = new JButton("u786Eu5B9A");
            button.addActionListener(e -> {
                String r = textField.getText();
                String n = textField_1.getText();
                textArea.setText("");
                try {
                    //传入参数生成表达式写入文件
                    HashSet<ExpressionResult> expressionResults = Generator.generateExpression(Integer.valueOf(r), Integer.valueOf(n));
                    Generator.generateFile(expressionResults);
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            });
            button.setBounds(533, 87, 113, 27);
            contentPane.add(button);
            JButton btnNewButton = new JButton("选择文件");
            btnNewButton.addActionListener(arg0 -> {
    
                JFileChooser jfc = new JFileChooser();
                jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
                jfc.showDialog(new JLabel(), "选择");
                File file = jfc.getSelectedFile();//得到文件
                if (file.isDirectory()) {
                    System.out.println("文件夹:" + file.getAbsolutePath());
                } else if (file.isFile()) {
                    System.out.println("文件:" + file.getAbsolutePath());
                }
                try {
                    //传入比对文件
                    Generator.CompareAnswers(file);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
            btnNewButton.setBounds(533, 39, 113, 27);
            contentPane.add(btnNewButton);
        }
    复制代码

      7. 程序入口

    复制代码
    public class AppEntry {
        public static void main(String[] args) {
            //新建窗口并显示
            GuiForOperator frame = new GuiForOperator();
            frame.setVisible(true);
            //启动线程监听队列取出表达式进行显示
            new Thread(() -> {
                while (true) {
                    try {
                        String expression = GuiForOperator.queue.take();
                        if (expression != null) {
                            frame.textArea.append(expression + "
    ");
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
    复制代码

     参考资料:https://www.cnblogs.com/hzkkk/p/9727038.html

  • 相关阅读:
    java加载类的方法1.classloader 2.class.forName()
    servlet与线程与jdbc connection的关系
    static再次深入理解
    多线程读某个共享变量有时候也要给读方法加锁
    多线程读一个全局变量要不要加锁?还是说只是当修改全局变量的时候才要加锁?
    接口耗时打印并统计
    Java从设计模式[本场比赛状态转换武器]状态分析(State)模式
    Openstack中间DVR Part1 -- 东西走向的交通处理
    写酷“大神”的公开信
    从反思谈论阵列和指针的几个问题,腾讯的笔名
  • 原文地址:https://www.cnblogs.com/xugama/p/15348356.html
Copyright © 2011-2022 走看看