ツイニングプロジェクト(javaは達成)

、GitHubのプロジェクト住所:https://github.com/734635746/MyApp

 


 

二、PSP用フォーム

 

PSP2.1 パーソナルソフトウェアプロセス段階 推定時間がかかる(分) 実際の時間がかかる(分)
プランニング 計画 30 30
・見積り •このタスクが必要と推定どのくらいの時間 30 30
開発 開発    
・分析 ・分析ニーズ  120 120
・デザインスペック 設計ドキュメントの生成 60 70
・デザインレビュー ・デザインレビュー  40 60
・コーディング標準 ・コードの仕様 30 40
・ 設計 ・具体的な設計 100 90
・コーディング ・具体的なコーディング 800 800
・コードレビュー ・コードレビュー  60 60 
・テスト ・テスト(セルフテスト、コードを変更し、変更を提出)    
報告 レポート    
・ 試験報告書 ・テストレポート    
・サイズ測定 ・コンピューティングのワークロード    
・死後&プロセス改善計画 ・後知恵、およびプロセス改善計画を提案します    
トータル      

 

 


第三に、パフォーマンス分析

 @謝航空機 


第四に、設計と実装プロセス

  タイトルを読んだ後、私たち二人はクラス式の設計プロセスを考え始めています。オペレータのランダムに生成された数とクラス属性は、対応する処理は、クラスの算出方法により行われます。しかし、最終的には直接計算式生成プロセスの文字列を選択しました。このようにして、より直接的で便利なプロセスになります。

   具体的なアイデアや発現値の数と範囲を制御するために-n -rパラメータを受信します。ランダムに生成された文字列演算子及びオペランドによって計算式を生成します。ランダムな文字列の計算式を生成する際に乱数によってブラケットの計算式を用いて生成されてもよいです。次いで困難アイテムのランダムに生成された結果値算出式を算出する方法です。

   式オペレータは優先順位番号とランダム(1-3)のタイプであるため、オペレータは、高および低点を有する、ブラケットをもたらす計算順序が同じではありません。これは、計算の結果は、最終的にすることによって情報へのアクセスを通じて問題を発見され、複雑になります操車場アルゴリズム解決します。アルゴリズムをスケジューリングするアルゴリズムによって計算式問題の結果を解決することができる古典的なアルゴリズムの後置式に中置式を変換するために使用されるフィールドであってもよいです。

   このプロジェクトでは、すべてのオペランドは、スコアとして算出整数(分母は整数)を算出します。この画分のために設計されたクラス画分処理する、分数の整数部、分子部分、分母部分。これの利点は、分数表記法によって行うことができる2つのオペランドの動作を実行する時間です。

   プロジェクト構造を以下に示します:

    

 

機能コードの構造:

   分数:分数クラス、オペランドの計算のすべての項目が計算分数オブジェクトに変換され

   SymbolConstant:プロジェクトで使用する定数を定義する定数クラス

   CalculateUtil:計算ツールは、式Aの計算に必要なデータテーブルをカプセル化する方法

   ExpressionUtil:算術式ツール、所望の表現を生成するパッケージ方法

   NumberUtil:メソッドオペランドオペランド生成ツール、パッケージのための

   OperatorUtil:必要な演算子を生成する方法を封入

   PrintFileUtil:回答検証タイトルファイルを生成するためのカプセル化方法および

   メイン:特定の関数呼び出しのパラメータを受信するためのメインクラス、

 

 関係のフローチャートを呼び出します。

 

 


V.コード説明

  スコアカテゴリ

public class Fraction {
    private int inter;//整数部分
    private int numerator;//分子
    private int denominator;//分母
        
  //省略构造方法 set、get方法  
}

 运算式生成的代码

 /**
     * 根据运算符数组和操作数数组生成运算式表达式
     * @param curOperators 运算符数组
     * @param curNumbers 操作数数组
     * @return 运算式字符串
     */
    private static String getExpressStr(Character[] curOperators, String[] curNumbers){  ---->运算符数组和操作数数组是随机生成的,由于生成的相关代码比较简单这里就不展示了
        //操作数的数量
        int number = curNumbers.length;
        //随机判断是否生成带括号的运算式
        int isAddBracket = (int)(Math.random()*10) % 2;  -----> 该运算式是否带括号也是通过随机数来判断的
        //随机生成器
        Random random = new Random();

        if(isAddBracket==1){//生成带括号的表答式
            //当标记为1时代表该操作数已经添加了左括号
            int[] lStamp = new int[number];         --------->这两个数组是用来标记当前操作数是否添加了左、右括号
            //当标记为1时代表该操作数已经添加了右括号    
            int[] rStamp = new int[number];
            //遍历操作数数组,随机添加括号
            for (int index=0;index<number-1;index++) {   -------------->遍历操作数来随机添加左括号,这里没有遍历到最后一个操作数是由于最后一个操作数不可能添加左括号
                int n = (int)(Math.random()*10) % 2;
                if(n == 0 && rStamp[index] != 1) {//判断当前操作数是否标记了左括号
                    lStamp[index] = 1;//标记左括号
                    curNumbers[index] = "(" + curNumbers[index];  //操作数之前加上左括号
                    int k = number - 1;
                    //生成右括号的位置
                    int rbracketIndex = random.nextInt(k)%(k-index) + (index+1);
                    //如果当前操作数有左括号,则重新生成右括号位置
                    while (lStamp[rbracketIndex] == 1){
                        rbracketIndex = random.nextInt(k)%(k-index) + (index+1);
                    }
            rStamp[rbracketIndex] = 1; curNumbers[rbracketIndex]
= curNumbers[rbracketIndex] +")"; } } } //将运算符数组和操作数数组拼成一个运算式字符串 StringBuilder str = new StringBuilder(curNumbers[0]); for (int k = 0; k < curOperators.length; k++) { str.append(curOperators[k]).append(curNumbers[k + 1]); } return str.toString(); }


   运算式结果计算相关代码

/**
 * @author liuyoubin
 * @date 2019/9/28 - 15:06
 * 运算工具类
 */
public class CalculateUtil {

     运算式的结果计算采用了调度场算法吗,该算法的思想是将我们常见的中缀表达式转成后缀表达式。算法如下:
  • 当还有记号可以读取时:
  • 读取一个记号。
  • 如果这个记号表示一个数字,那么将其添加到输出队列中。
  • 如果这个记号表示一个函数,那么将其压入栈当中。
  • 如果这个记号表示一个函数参数的分隔符(例如,一个半角逗号,):
  • 从栈当中不断地弹出操作符并且放入输出队列中去,直到栈顶部的元素为一个左括号为止。如果一直没有遇到左括号,那么要么是分隔符放错了位置,要么是括号不匹配。
  • 如果这个记号表示一个操作符,记做o1,那么:
  • 只要存在另一个记为o2的操作符位于栈的顶端,并且
  • 如果o1是左结合性的并且它的运算符优先级要小于或者等于o2的优先级,或者
  • 如果o1是右结合性的并且它的运算符优先级比o2的要低,那么
  • 将o2从栈的顶端弹出并且放入输出队列中(循环直至以上条件不满足为止);
    • 然后,将o1压入栈的顶端。
    • 如果这个记号是一个左括号,那么就将其压入栈当中。
    • 如果这个记号是一个右括号,那么:
    • 从栈当中不断地弹出操作符并且放入输出队列中,直到栈顶部的元素为左括号为止。
    • 将左括号从栈的顶端弹出,但并不放入输出队列中去。
    • 如果此时位于栈顶端的记号表示一个函数,那么将其弹出并放入输出队列中去。
    • 如果在找到一个左括号之前栈就已经弹出了所有元素,那么就表示在表达式中存在不匹配的括号。
    • 当再没有记号可以读取时:
    • 如果此时在栈当中还有操作符:
    • 如果此时位于栈顶端的操作符是一个括号,那么就表示在表达式中存在不匹配的括号。
    • 将操作符逐个弹出并放入输出队列中。
    • 退出算法
/**
     * 采用调度场算法,获取指定运算式的结果值
     *
     * @param express 运算式
     * @return
     */
    public static String getExpressValue(String express){
        //运算符栈,用于存放运算符包括 +、-、*、÷、(、)
        Stack<Character>  operators = new Stack<Character>();
        //操作数栈,用于存放操作数
        Stack<Fraction> fractions = new Stack<Fraction>();
        //将表达式字符串转成字符数组
        char[] chars = express.toCharArray();
        //遍历获取处理
        for (int i=0;i<chars.length;i++) {
            //获取当前的字符
            char c = chars[i];

            if(c=='('){//如果是左括号,入栈
                operators.push(c);
            }else if(c==')'){//当前字符为右括号
                //当运算符栈顶的元素不为‘(’,则继续
                while(operators.peek()!='('){
                    //拿取操作栈中的两个分数
                    Fraction fraction1 = fractions.pop();
                    Fraction  fraction2 = fractions.pop();
                    //获取计算后的值
                    Fraction result = calculate(operators.pop(), fraction1.getNumerator(), fraction1.getDenominator(),
                            fraction2.getNumerator(), fraction2.getDenominator());
                    //将结果压入栈中
                    fractions.push(result);
                }
                //将左括号出栈
                operators.pop();
            }else if(c=='+'||c=='-'||c=='*'||c=='÷'){//是运算符
                //当运算符栈不为空,且当前运算符优先级小于栈顶运算符优先级
                while(!operators.empty()&&!priority(c, operators.peek())){
                    //拿取操作栈中的两个分数
                    Fraction fraction1 = fractions.pop();
                    Fraction  fraction2 = fractions.pop();
                    //获取计算后的值
                    Fraction result = calculate(operators.pop(), fraction1.getNumerator(), fraction1.getDenominator(),
                            fraction2.getNumerator(), fraction2.getDenominator());
                    //将结果压入栈中
                    fractions.push(result);
                }
                //将运算符入栈
                operators.push(c);
            }else{//是操作数
                if(c>='0'&&c<='9'){
                    StringBuilder buf = new StringBuilder();
                    //这一步主要是取出一个完整的数值 比如 2/5、9、9/12
                    while(i<chars.length&&(chars[i]=='/'||((chars[i]>='0')&&chars[i]<='9'))){
                        buf.append(chars[i]);
                        i++;
                    }
                    i--;
                    //到此 buf里面是一个操作数
                    String val = buf.toString();
                    //标记‘/’的位置
                    int flag = val.length();
                    for(int k=0;k<val.length();k++){
                        if(val.charAt(k)=='/'){//当获取的数值存在/则标记/的位置,便于接下来划分分子和分母生成分数对象
                            flag = k;
                        }
                    }
                    //分子
                    StringBuilder numeratorBuf = new StringBuilder();
                    //分母
                    StringBuilder denominatorBuf = new StringBuilder();
                    for(int j=0;j<flag;j++){
                        numeratorBuf.append(val.charAt(j));
                    }
                    //判断是否为分数
                    if(flag!=val.length()){
                        for(int q=flag+1;q<val.length();q++){
                            denominatorBuf.append(val.charAt(q));
                        }
                    }else{//如果不是分数则分母计为1
                        denominatorBuf.append('1');
                    }
                    //入栈
                    fractions.push(new Fraction(Integer.parseInt(numeratorBuf.toString()), Integer.parseInt(denominatorBuf.toString())));
                }
            }
        }

        while(!operators.empty()){
            Fraction fraction1 = fractions.pop();
            Fraction  fraction2 = fractions.pop();

            //获取计算后的值
            Fraction result = calculate(operators.pop(), fraction1.getNumerator(), fraction1.getDenominator(),
                    fraction2.getNumerator(), fraction2.getDenominator());

            //将结果压入栈中
            fractions.push(result);
        }

        //计算结果
        Fraction result = fractions.pop();
        //获取最终的结果(将分数进行约分)
        return getFinalResult(result);

    }
---------------------------------------------------------------------------------------------------------------------------------------------
    private static String getFinalResult(Fraction result) {
        if(result.getDenominator()==0){
            return "0";
        }
        //获取最大公约数
        int gcd = gcd(result.getNumerator(),result.getDenominator());

        if(result.getDenominator()/gcd==1){//分母为1
            return String.valueOf(result.getNumerator()/gcd);
        }else{
            //如果分子大于分母则化成真分数的形式
            if(result.getNumerator()>result.getDenominator()){  
                result = getRealFraction(result);
                return result.getInter()+"'"+result.getNumerator()/gcd+"/"+result.getDenominator()/gcd;
            }else{
                return result.getNumerator()/gcd+"/"+result.getDenominator()/gcd;
            }
        }
    }
-----------------------------------------------------------------------------------------------------------------------------------------------
    /**
     * 化成真分数
     * @param result
     * @return
     */
    private static Fraction getRealFraction(Fraction result){
        int numerator = result.getNumerator();
        int denominator = result.getDenominator();
        //计算分子部分
        int newNumerator = numerator % denominator;
        //计算整数部分
        int inter = numerator/denominator;
        Fraction fraction = new Fraction(newNumerator, denominator);
        fraction.setInter(inter);                    ------------------------------->整数部分
        return fraction;
    }
-------------------------------------------------------------------------------------------------------------------------------------------------
    /**
     * 判断两个运算符的优先级
     * 当opt1的优先级大于opt2时返回true
     * 这是根据调度场算法给出的实现
     * @return
     */
    private static boolean priority(char opt1,char opt2){    --------------------------->只有当opt1的优先级小于或等于opt2的优先级时才放回true。这是根据调度场算法给出的实现
        if((opt1=='+'||opt1=='-')&&(opt2=='*'||opt2=='÷')){
            return false;
        }else if((opt1=='+'||opt1=='-')&&(opt2=='+'||opt2=='-')){
            return false;
        }else if((opt1=='*'||opt1=='÷')&&(opt2=='*'||opt2=='÷')){
            return false;
        }else{
            return true;
        }
    }
----------------------------------------------------------------------------------------------------------------------------------------------------
    /**
     * 对两个分数进行相应的运算,获取结果
     * @param opt 运算符
     * @param numerator1 分子1
     * @param denominator1 分母1
     * @param numerator2 分子2
     * @param denominator2 分母2
     * @return 结果
     */
    static Fraction calculate(Character opt,int numerator1,int denominator1,int numerator2,int denominator2){
        //结果数组,存放结果的分子与分母
        int[] result = new int[2];
        /**
         * 这里有一个陷阱,因为用于计算的两个数是通过栈来存储,所以取出计算结果的时候两个数的顺序会颠倒
         * 比如式子 1/2*9/12 我取出来的时候其实是 9/12 和 1/2 所以调用此函数的时候是calculate('*',9,12,1,2),所以下面的实现要注意不要踩坑
         */
        switch (opt){
            case '+':
                result[0] = numerator1*denominator2 + numerator2*denominator1; result[1]= denominator1*denominator2;
                return new Fraction(result[0],result[1]);
            case '-':
                result[0] = numerator2*denominator1 - numerator1*denominator2; result[1]= denominator1*denominator2;
                return new Fraction(result[0],result[1]);
            case '*':
                result[0] = numerator1*numerator2; result[1] = denominator1*denominator2;
                return new Fraction(result[0],result[1]);
            case '÷':
                result[0] = numerator2*denominator1; result[1] = numerator1*denominator2;
                return new Fraction(result[0],result[1]);
        }
        return new Fraction(result[0],result[1]);
    }
---------------------------------------------------------------------------------------------------------------------------------------------
    /**
     * 获取分子分母的最大公约数,辗转相除法
     * @param numerator 分子
     * @param denominator 分母
     * @return 最大公约数
     */
    private static int gcd(int numerator,int denominator){
        numerator = Math.abs(numerator);
        denominator = Math.abs(denominator);
        while (denominator != 0) {
            // 求余
            int remainder = numerator % denominator;
            // 交换数,等同递归调用
            numerator = denominator;
            denominator = remainder;
        }
        return numerator;
    }
}

 

 


 

六、测试运行 

 @谢飞机 

おすすめ

転載: www.cnblogs.com/liuyoubin/p/11605034.html