1. 程式人生 > >2016012063 小學四則運算練習軟件項目報告

2016012063 小學四則運算練習軟件項目報告

文檔 修改 兩個棧 一個數 括號運算符 表示 直接 mark Coding

源碼倉庫地址:https://coding.net/u/deervw/p/four-operations/git

一、需求分析

1.程序可從命令行接收一個輸入參數n,然後隨機產生n道加減乘除習題。

2.每個數字在 0 和 100 之間,運算符3到5個。

3.每道習題要包含3-5種運算符。

4.所出的練習題在運算過程中不得出現負數與非整數。

5.將學號與生成的n道練習題及其對應的正確答案輸出到文件“result.txt”中。

6.支持有括號的運算式,包括出題與求解正確答案;算式中存在的括號必須大於2個,且不得超過運算符的個數。

二、功能設計

1.基本功能:能夠根據用戶輸入的參數n隨機產生n道符合要求的練習題,自動算出答案,並將式子與答案以文檔的形式呈現。

2.擴展功能:支持有括號的運算式,包括出題與求解正確答案。(註意,算式中存在的括號必須大於2個,且不得超過運算符的個數。)

三、設計實現

我設計了一個主函數和兩個自定義函數,都在Main.java

1.判斷類

功能:帶參的有返回值的類,返回的是一個整數。通過返回的參數大小,從而來判斷符號的優先級。

關系:可以直接調用。

2.共因數divisor類

功能:帶參的有返回值的類,返回的是一個整數,該整數是兩個數的最大公因數。此類通過計算兩個數的最大公因數,生成化簡的最終結果。

關系:可以直接調用。

四、算法詳解

1.輸入產生的題目數n:判斷輸入的數是否為整數,若不是則拋出異常。

try {
    n=Integer.parseInt(args[0]);
    if(n<=0)System.out.println("請重新輸入整數!");
}
catch (Exception e){
    System.out.println("請重新輸入整數!");
}

2.生成隨機數和運算符:將運算符存在一個數組arr裏,以便可以隨機生成;用rand()方法可以隨機生成0-1之間的數;若不能整除或出現負數可以使用循環重新生成a和b,直到滿足要求為止。

char[] arr= {‘+‘,‘-‘,‘*‘,‘÷‘};
int temp=rand.nextInt(4);
charArr
=arr[temp]; int a=rand.nextInt(100);//數字範圍 int b=rand.nextInt(100); while(a%b!=0)//判斷整除 { a=rand.nextInt(100); b=rand.nextInt(99)+1;//不能出現0 } while(a<b)//判斷是否出現負數 { a=rand.nextInt(100); b=rand.nextInt(100); }

3.最大公因數:保證生成的為真分數,用輾轉相除法

public static int divisor(int x,int y){
    while(1){
        if(x%y==0)return y;
        int temp=y;
        y=x%y;
        x=temp;
    }
}

4.計算後綴表達式:我創建了一個棧ljk,保存的是char類型的字符,然後我int了一個op1來分別保存兩個棧頂的操作數,所以這裏先用到了String.valueOf方法先將char轉換成String,然後使用Integer.parseInt方法。

 int op1 = Integer.parseInt(String.valueOf(lkj.pop()));
 int op2 = Integer.parseInt(String.valueOf(lkj.pop()));
 int op = op1 - op2;
 lkj.push(op);

五、測試運行

技術分享圖片

技術分享圖片

六、代碼展示

將中序表達式轉化為後序表達式:

static bool isNumber(string message)
        {
            //判斷是否為整數字符串    
            int result = -1;   //result 定義為out 用來輸出值  
            try
            {
                result = Convert.ToInt32(message);
                return true;
            }
            catch
            {
                return false;
            }
        }

        //判斷操作符優先級大小  
        static bool comparePriority(string op1, string op2)
        {
            return getPriorityValue(op1) > getPriorityValue(op2);
        }

        private static int getPriorityValue(string op1)
        {
            throw new NotImplementedException();
        }

        static Stack<string> changeExpression(List<string> beforeExps)
        {
            Stack<string> operand = new Stack<string>();//操作數  
            Stack<string> opertor = new Stack<string>();//操作符  
            //遍歷中序表示  
            int length = beforeExps.Count;
            int len = opertor.Count;
            //判斷是否為操作數    
            for (int i = 0; i < length; i++)
            {
                string c = beforeExps[i];
                if (isNumber(c))
                {
                    //操作數 存在操作數棧  
                    operand.Push(c);
                }
                else
                {
                    //若運算符為"("直接存入到運算符棧中   
                    if (c == "(")
                    {
                        opertor.Push(c);
                    }
                    else if (c == ")")
                    {
                        //該運算符為右括號")",則輸出運算符堆棧中的運算符到操作數堆棧,直到遇到左括號為止。 將"("出棧    
                        while (opertor.Peek() != "(")
                        {
                            string stringvalue = opertor.Pop();
                            operand.Push(stringvalue);
                        }
                        opertor.Pop();
                    }
                    else
                    { 
                        // 該運算符為非括號運算符
                        if (len <=  0)
                        {
                            opertor.Push(c);
                            continue;
                        }
                        //若運算符堆棧棧頂的運算符為括號,則直接存入運算符堆棧。  
                        //符合為左括號 直接存入運算符  
                        if (opertor.Peek() == "(")
                        {
                            opertor.Push(c);
                        }
                        else
                        {
                            //若比運算符堆棧棧頂的運算符優先級高或相等,則直接存入運算符堆棧。    
                            if (comparePriority(c, opertor.Peek()))
                            {
                                opertor.Push(c);
                            }
                            else
                            {
                                // 若比運算符堆棧棧頂的運算符優先級低,則輸出棧頂運算符到操作數堆棧,並將當前運算符壓入運算符堆棧。  
                                string stringvalue = opertor.Pop();
                                operand.Push(stringvalue);
                                opertor.Push(c);
                            }

                        }
                    }
                }
            }
            //當表達式讀取完成後運算符堆棧中尚有運算符時,則依序取出運算符到操作數堆棧,直到運算符堆棧為空。  
            while (len > 0)
            {
                string stringvalue = opertor.Pop();
                operand.Push(stringvalue);
            }
            //反轉operand 獲取正常的後綴表達式  
            Stack<string> resultSt = new Stack<string>();
            while (len > 0)
            {
                string stringvalue = operand.Pop();
                resultSt.Push(stringvalue);
            }
            return resultSt;
        }

七、總結:

所謂“模塊化”就是要功能獨立,功能塊裏要明確和調試好函數之間的調用關系,以便降低程序的復雜度和更進一步的維護。比如,在我的程序中,產生隨機數和計算題目這兩個功能是分開的,只要在產生隨機數的程序裏確定好操作數是合法的,那麽計算部分可以和操作數之間做到完全獨立。

八、展示PSP

PSP2.1Personal Software Process Stages預估耗時(小時)實際耗時(小時)
Planning 計劃 1 1
· Estimate · 估計這個任務需要多少時間 20 24
· Analysis · 需求分析 (包括學習新技術) 1 4
· Design Spec · 生成設計文檔 0.5 0.5
· Design Review · 設計復審 (和同事審核設計文檔) 0.5 0.5
· Coding Standard · 代碼規範 (為目前的開發制定合適的規範) 1.5 1
· Design · 具體設計 2 2.5
· Coding · 具體編碼 2 3
· Code Review · 代碼復審 2 2
· Test · 測試(自我測試,修改代碼,提交修改) 2 1
Reporting 報告 1 1.5
· Test Report · 測試報告 1.5 2
· Size Measurement · 計算工作量 1.5 1
· Postmortem & Process Improvement Plan · 事後總結, 並提出過程改進計劃 1 1

2016012063 小學四則運算練習軟件項目報告