1. 程式人生 > 實用技巧 >結對專案:自動生成小學四則運算題目

結對專案:自動生成小學四則運算題目

結對程式設計

github地址

這個作業屬於哪個課程 https://edu.cnblogs.com/campus/gdgy/Networkengineering1834
這個作業要求在哪裡 https://edu.cnblogs.com/campus/gdgy/Networkengineering1834/homework/11148
這個作業的目標 學習協作程式設計

張浩輝(3118005347),張澍(3118005348)

一、需求分析

需求是需要是需要實現一個自動生成小學四則運算題目的命令列程式

包含加減乘除和括號。這涉及到二叉樹的知識。

並且能夠控制生成題目的個數和控制題目中的數值範圍。

能把題目和答案進行輸出,能對使用者答案與標準答案作比對。因此涉及到io操作。

二、實現思路

  1. 表示式構建

    在網上參考了很多種方法,主要是兩種方法實現,二叉樹或者是棧。

    這裡用的是二叉樹方法,在二叉樹中,度為0的是運算數,其餘的是運算子號。

    在每一個節點(包含符號節點)都需要儲存當前節點以下的計算結果,符號節點還需要儲存當前的符號型別。

  2. 運算數形式

    運算數使用分數進行儲存,在構建分數的情況下會對一些異常進行處理比如分母為零的情況,並自動使用輾轉相除法對分子分母求最大公約數

  3. 表示式重複檢驗

    重寫hashcode方法可以實現兩個二叉樹是否為相同的樹,即能實現比對兩個表達的查重

  4. 運算結果不能出現負數

    通過交換符號節點下的左右子樹即可實現

三、具體實現

3.1 檔案目錄

├── pom.xml
├── src
│ ├── main
│ │ └── java
│ │     └── com
│ │         └── free
│ │             ├── MainStart.java 主啟動類
│ │             ├── pojo 實體類
│ │             │ ├── Check.java 檢測使用者答案 
│ │             │ ├── Creator.java 生成表示式
│ │             │ ├── Expression.java 表示式類
│ │             │ ├── MyNumber.java 運算數類
│ │             │ ├── Node.java運算數節點類
│ │             │ └── Onode.java 符號節點類
│ │             └── util
│ │                 └── FileUtils.java 檔案輸入輸出類
│ └── test
│     └── java
│         ├── ExpressionTest.java
│         └── FractionTest.java


3.2 類圖

3.3核心實現

計算數

package com.free.pojo;

import lombok.Data;

/**
 * @ClassName MyNumber
 * @Description 計算數
 * @Author Free
 * @Date2020/10/9 20:22
 * @Version V1.0
 **/
@Data
public class MyNumber {
    /**
     * 分子
     */
    private int up;
    /**
     * 分母,不能為0,預設為1
     */
    private int down = 1;
    //設定分子和分母
    public MyNumber(int a, int b) {
        setMyNumber(a, b);
    }
    //看當前分數是否為負數
    boolean isNegative() {
        //結果預設是正數
        boolean isNagitiveAB = false;
        if (up * down < 0) {
            isNagitiveAB = true;
        }
        return isNagitiveAB;
    }
    /**
     * 設定分子和分母
     * @param up
     * @param down
     */
    public void setMyNumber(int up,int down){
        if (down == 0){
            throw new RuntimeException("分母不能為0");
        }
        //結果預設是正數
        int isNagitive = 1;
        //調整符號,分母只能為正數
        if (up * down < 0) {
            isNagitive = -1;
        }
        up = Math.abs(up);
        down = Math.abs(down);
        //最大公因數
        int greatest_Common_Factor = divisionAlgorithm(up, down);
        //化簡
        this.up = up * isNagitive / greatest_Common_Factor;
        this.down = down / greatest_Common_Factor;
    }
    /**
     * 求最大公因數,輾轉相除法
     * @param a
     * @param b
     * @return
     */
    private int  divisionAlgorithm(int a, int b) {
        int big = a;
        if (big == 0){
            return 1;
        }
        int small = b;
        //讓a成為最大的
        if (a < b) {
            big = b;
            small = a;
        }
        int mod = big % small;
        return mod == 0 ? small : divisionAlgorithm(small, mod);
    }


    /**
     * 功能描述: 通過表示式得到分子和分母,都未經過簡化 "1'21/22"
     * @Param: [result]
     * @Return:
     * @Author: Free
     * @Date: 2020/10/9 21:19
     */
    public MyNumber(String result) {
        result.trim();
        int up_index = result.indexOf("/");
        int a1_index = result.indexOf("'");

        //不是分式的時候
        if (up_index == -1) {
            up = Integer.valueOf(result);
        }
        //是分式的時候
        else {
            //分母
            down = Integer.valueOf(result.substring(up_index + 1));
            //真分數
            if (a1_index == -1) {
                up = Integer.valueOf(result.substring(0, up_index));
            }
            //帶分數
            else {
                int a1 = Integer.valueOf(result.substring(0, a1_index));
                int a0 = Integer.valueOf(result.substring(a1_index + 1, up_index));
                up = a1 * down + a0;
            }
        }
        setMyNumber(up, down);
    }

   /**
    * 功能描述: 隨機生成一個用來運算的分數(多種形式)
    *
    * @Param: []
    * @Return: com.free.pojo.MyNumber
    * @Author: Free
    * @Date: 2020/10/9 21:16
    */
    public static MyNumber generateMyNumber() {
        //a.b 都是大於等於0的
        int up = Creator.getRandomInRange(Expression.numRange);
        int down = Creator.getRandomInRange(Expression.numRange);
        //分母為0
        while (down == 0) {
            down = Creator.getRandomInRange(Expression.numRange);
        }
        MyNumber result = new MyNumber(up,down);
        return result;
    }



    /**
     * 功能描述: <br>加法
     * 〈〉
     * @Param: [right]
     * @Return: com.free.pojo.MyNumber
     * @Author: Free
     * @Date: 2020/10/9 21:22
     */
    public MyNumber add(MyNumber right) {
        // a/b+c/d =(ad+bc)/bd
        return new MyNumber(
                this.up * right.down + this.down * right.up,
                this.down * right.down
        );
    }

    /**
     * 功能描述: <br>
     * 〈〉
     * @Param: [right]減法
     * @Return: com.free.pojo.MyNumber
     * @Author: Free
     * @Date: 2020/10/9 21:22
     */
    public MyNumber subtract(MyNumber right) {
        // a/b-c/d =(ad-bc)/bd
        return new MyNumber(
                this.up * right.down - this.down * right.up,
                this.down * right.down
        );
    }

    /**
     * 功能描述: <br>乘法
     * 〈〉
     * @Param: [right]
     * @Return: com.free.pojo.MyNumber
     * @Author: Free
     * @Date: 2020/10/9 21:22
     */
    public MyNumber multiply(MyNumber right) {
        // a/b * c/d = ac / bd
        return new MyNumber(
                this.up * right.up,
                this.down * right.down
        );
    }

    /**
     * 功能描述: <br>除法
     * 〈〉
     * @Param: [right]
     * @Return: com.free.pojo.MyNumber
     * @Author: Free
     * @Date: 2020/10/9 21:22
     */
    public MyNumber divide(MyNumber right) {
        // a/b  /  c/d = ad / bc
        return new MyNumber(
                this.up * right.down,
                this.down * right.up
        );
    }

    //將a,b轉化為表示式
    @Override
    public String toString() {
        //不是分式
        if (down == 1)
            return String.valueOf(up);
            //真分式
        else {
            int i = up / down;
            //餘數
            int j = up % down;
            if (i != 0) {
                return String.format("%d'%d/%d", i, j, down);
            } else {
                return String.format("%d/%d", up, down);
            }
        }
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) return false;

        MyNumber fraction = (MyNumber) o;

        if (up != fraction.up) return false;
        return down == fraction.down;
    }

    //根據分子和分母
    @Override
    public int hashCode() {
        int result = 37853 * up + down;
        return result;
    }
}

在構建一個運算數的時候,有隨機構建功能和手動輸入功能,在生成的過程中有自動轉化功能,能夠保證每一個運算數是正確的,並且都是分數形式儲存,用up表示分子部分,down表示分母部分。這樣直觀,並且在運算的過程中可以通過通分等方式進行計算。

如:

  1. 1/2 + 3/4 = 1x4+3x2 /2x4

  2. 1/2 x 3/4 = 1x3 / 2x4

  3. 1/2 - 3/4 = 1x4 - 3x2 /2x4

  4. 1/2 ÷ 3/4 = 1x3 + 2x4 /2 x3

四、效能測試

Telemetries

Live Memory

五、執行結果

生成聯絡檔案和答案檔案:

校對答案生成成績檔案:

六、 PSP表格

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 130 150
· Estimate · 估計這個任務需要多少時間 110 150
Development 開發 1660 2045
· Analysis · 需求分析 (包括學習新技術) 100 160
· Design Spec · 生成設計文件 100 120
· Design Review · 設計複審 (和同事稽核設計文件) 60 80
· Coding Standard · 程式碼規範 (為目前的開發制定合適的規範) 60 75
· Design · 具體設計、 120 130
· Coding · 具體編碼 1000 1200
· Code Review · 程式碼複審 100 160
· Test · 測試(自我測試,修改程式碼,提交修改) 120 120
Reporting 報告 120 210
· Test Report · 測試報告 60 150
· Size Measurement · 計算工作量 30 30
· Postmortem & Process Improvement Plan · 事後總結, 並提出過程改進計劃 30 30
合計 1910 2570