個人第2次作業:熟悉使用工具


Gayhub 項目地址

初始化及克隆倉庫,創建項目

初始化並克隆倉庫:

40184@Rongz MINGW32 ~
$ cd e:

40184@Rongz MINGW32 /e
$ cd RongGit/

40184@Rongz MINGW32 /e/RongGit
$ git init
Initialized empty Git repository in E:/RongGit/.git/

40184@Rongz MINGW32 /e/RongGit (master)
$ git clone https://github.com/Cherish599/AchaoCalculator.git
Cloning into 'AchaoCalculator'...
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 0), reused 4 (delta 0), pack-reused 0
Unpacking objects: 100% (6/6), done.

創建項目:

代碼編寫

工具類 Result:

用途封裝代碼執行結果

/// <summary>
/// 前綴表達式字符串
/// </summary>
internal StringBuilder infixFormula;

/// <summary>
/// 后綴表達式隊列
/// </summary>
internal Queue<string> formulaQueue;

/// <summary>
/// 計算結果
/// </summary>
internal int result;

中綴表達式式生成:

解決思路:

問題化簡:通過觀察我們知道,每一個表達式都有三部分組成——乘除法表達式部分、加減法表達式部分、和連接二者的加減號部分。如1+2+3 * 4/2,就是1+2和 3 * 4/2及+組成。所以我們大體思路就是創建兩個分別生成乘除法表達式和加減法表達式的函數,然后用加減法將他們組合起來。

  1. multipleFormulaGenerator(int count)函數

    給定一個乘除法表達式所含操作數的個數,生成一個隨機的乘除法表達式,並以隊列的形式返回

    比如:count=3,輸出可能是1 * 2 * 3

    ​ count=4,輸出可能是1 * 2 * 3 / 2

    1. 解決被除數和除數整除的問題思路
      1. 先生成一個數 num ,將它放入隊列
        1. 生成一個符號(* 或 /)
          1. 如果是 * :新生成一個數 num2,並與之前 num 相乘 ,用 num 記錄相乘的結果
          2. 如果是 / :尋找一個 num 的因式作為除數
      2. 輸出隊列
    2. 解決尋找一個數所有因式的思路(chooseRandomFactor(int num)實現)
      1. i 從 1 遍歷到 根號 num
      2. 如果 num % i==0
      3. 將 i 和 num/i 存入一個數組(存入的兩個數就是num的兩個因式)
      4. 隨機返回數組中的一個因式,就得到了 num 的一個隨機的因式
    
    /// <summary>
    /// 給定一個乘除法表達式所含操作數的個數,生成一個隨機的乘除法表達式,並以隊列的形式返回
    /// </summary>
    /// <param name="count"> 符號數個數 </param>
    /// <returns> 乘除法表達式隊列 </returns>
    public static Queue<string> multipleFormulaGenerator(int count)
    {
        Queue<string> queue = new Queue<string>();
        int num = random.Next(maxNum) + 1;
        queue.Enqueue(num.ToString());
        while (--count > 0)
        {
            string option = op[2 + random.Next(2)];
            if (string.ReferenceEquals(option, "/"))
            {
                int factor = chooseRandomFactor(num);
                queue.Enqueue(option);
                queue.Enqueue(factor.ToString());
                num /= factor;
            }
            else
            {
                int num2 = random2.Next(maxNum) + 1;
                queue.Enqueue(option);
                queue.Enqueue(num2.ToString());
                num *= num2;
            }
        }
        return queue;
    }
    
    /// <summary>
    /// 從一個數的所有因式中隨機選擇一個返回
    /// </summary>
    /// <param name="num"> 數 </param>
    /// <returns> num 的一個因式 </returns>
    private static int chooseRandomFactor(int num)
    {
        int[] arr = new int[num + 1];
        int size = 0;
        for (int i = 1; i <= Math.Sqrt(num); i++)
        {
            if (num % i == 0)
            {
                arr[size++] = i;
                arr[size++] = num / i;
            }
        }
        int r = random2.Next(size);
        return arr[r];
    }
    
  2. additionAndSubtractionFormulaGenerator(int count)函數

    給定一個加減法表達式所含操作數的個數,生成一個隨機的加減法表達式,並以隊列的形式返回

    count 含義如 multipleFormulaGenerator() 的 count

    思路簡單,看代碼

    
    /// <summary>
    /// 給定一個加減法表達式所含操作數的個數,生成一個隨機的加減法表達式,並以隊列的形式返回
    /// </summary>
    /// <param name="count"> 符號數個數 </param>
    /// <returns> 加減法表達式隊列 </returns>
    public static Queue<string> additionAndSubtractionFormulaGenerator(int count)
    {
        Queue<string> queue = new Queue<string>();
        int num = random.Next(maxNum) + 1;
        queue.Enqueue(num.ToString());
        while (--count > 0)
        {
            string option = op[random.Next(2)];
            queue.Enqueue(option);
            queue.Enqueue((random.Next(maxNum) + 1).ToString());
        }
        return queue;
    }
    
  3. formulaMaker()函數

    隨機生成多個乘除法表達式和加減法表達式,並將他們用 + 或 - 號拼接

    /// <summary>
    /// 表達式生成器
    /// </summary>
    /// <returns> 中綴表達式隊列 </returns>
    public static Result formulaMaker()
    {
        Queue<string> queue = new Queue<string>();
        StringBuilder sb = new StringBuilder();
        int maxNumCount2 = maxNumCount;
        while (maxNumCount2-- > 0)
        {
            string option = op[random.Next(2)];
            int nextBoolean = random.Next(0,1);
    
            if (nextBoolean==0)
            {
                Queue<string> queue1 = multipleFormulaGenerator(random.Next(3) + 1);
                mergeQueue(queue, queue1);
            }
            else
            {
                mergeQueue(queue, additionAndSubtractionFormulaGenerator(random2.Next(3) + 1));
            }
            if (maxNumCount2 != 0)
            {
                queue.Enqueue(op[random.Next(2)]);
            }
        }
        foreach (string s in queue)
        {
            sb.Append(s);
        }
        return new Result(sb, queue);
    }
    
  4. changeToPostfix(Queue queue)函數

    將formulaMaker()生成的中綴表達式,轉化為后綴表達式(4+4/2 * 3-5 * 2 --> 442/3 * +52 * - )

    1. 如果是操作數直接輸出到操作數隊列
    2. 如果是操作符
      1. 操作符棧為空直接輸出到操作符棧
      2. 如果不為空,循環判斷如果 操作符棧頂的符號優先級大於等於當前符號,則將操作符棧的符號輸出,然后再將操作數入棧。否則將操作數壓棧
    3. 將操作符棧的所有元素輸出
    /// <summary>
    /// 中綴表達式轉后綴表達
    /// </summary>
    /// <param name="queue"> 中綴表達式隊列 </param>
    /// <returns> 后綴表達式堆棧 </returns>
    public static Queue<string> changeToPostfix(Queue<string> queue)
    {
        Queue<string> queue2 = new Queue<string>(); // 保存操作數
        Stack<string> stack2 = new Stack<string>(); // 保存操作符
        while (queue.Count > 0)
        {
            string symbol = queue.Dequeue();
            if (precedence(symbol) > 0)
            { //檢查symbol是否是一個操作數
                while (stack2.Count > 0 && precedence(stack2.Peek()) >= precedence(symbol))
                {
                    queue2.Enqueue(stack2.Pop());
                }
                stack2.Push(symbol);
            }
            else
            { //symbol 不是一個操作數
                queue2.Enqueue(symbol);
            }
        }
        while (stack2.Count > 0)
        {
            queue2.Enqueue(stack2.Pop());
        }
        return queue2;
    }
    
  5. calculate(Queue stack)

    將 changeToPostfix()生成的后綴表達式進行計算求值

    1. 如果不是操作符直接輸出到操作數棧
    2. 如果是操作符,將操作數棧棧頂的兩個操作數彈出做運算,存入操作數棧
      3.最后將操作數棧頂的的元素彈出
    /// <summary>
    /// 計算函數
    /// 用於計算后綴表達式的值
    /// </summary>
    /// <param name="queue"> 后綴表達式堆棧 </param>
    /// <returns> 計算結果 </returns>
    public static int calculate(Queue<string> queue)
    {
        Stack<string> stack1 = new Stack<string>(); // 保存操作數
        Stack<string> stack2 = new Stack<string>(); // 保存操作符
        foreach (string symbol in stack)
        {
            if (!symbol.Equals("+") && !symbol.Equals("-") && !symbol.Equals("/") && !symbol.Equals("*"))
            {
                stack1.Push(symbol);
            }
            else
            {
                int a = int.Parse(stack1.Pop()), b = int.Parse(stack1.Pop());
                switch (symbol)
                {
                    case "+":
                        stack1.Push((a + b).ToString());
                        break;
                    case "-":
                        stack1.Push((b - a).ToString());
                        break;
                    case "*":
                        stack1.Push((a * b).ToString());
                        break;
                    default:
                        stack1.Push((b / a).ToString());
                        break;
                }
            }
        }
        return int.Parse(stack1.Pop());
    }
    

輸出到文件

/// <summary>
/// 將題目和答案打印到文件
/// 默認目錄 E:\\
/// </summary>
public static void printToFile()
{
    int i = 1000, k = 1;
    string pathProblem = "E:\\Problem.txt", pathAnswer = "E:\\Answer.txt";
    FileStream f1 = new FileStream(pathProblem, FileMode.Create, FileAccess.ReadWrite);
    FileStream f2 = new FileStream(pathAnswer, FileMode.Create, FileAccess.ReadWrite);
    StreamWriter sw1 = new StreamWriter(f1);
    StreamWriter sw2 = new StreamWriter(f2);
    while (i-- > 0)
    {
        Result result = formulaMaker();
        Queue<string> queue = changeToPostfix(result.formulaQueue);
        int res = calculate(queue);
        result.result = res;

        sw1.Write(k + "." + result.infixFormula + "=\r\n");
        sw2.Write(k++ + "." + result.getResult() + "\r\n");
    }
    sw1.Close();
    sw2.Close();
}

單元測試

創建測試項目:

添加引用:

運行測試:和結果相符

效能工具

修改主函數:

public static void Main(string[] args)
{
    for (int i = 0; i < 10000000; i++) {
        Result result = formulaMaker();
        Queue<string> postfixQueue = changeToPostfix(result.FormulaQueue);
        int res = calculate(postfixQueue);
        Console.WriteLine("formula:" + result.infixFormula);
        Console.WriteLine("result:" + res);
    }
}

效能分析報告:

創建詳細的報告:

提交代碼

40184@Rongz MINGW32 /e/RongGit (master)
$ git add AchaoCalculator
warning: adding embedded git repository: AchaoCalculator
hint: You've added another git repository inside your current repository.
hint: Clones of the outer repository will not contain the contents of
hint: the embedded repository and will not know how to obtain it.
hint: If you meant to add a submodule, use:
hint:
hint:   git submodule add <url> AchaoCalculator
hint:
hint: If you added this path by mistake, you can remove it from the
hint: index with:
hint:
hint:   git rm --cached AchaoCalculator
hint:
hint: See "git help submodule" for more information.

40184@Rongz MINGW32 /e/RongGit (master)
$ git commit -m "release version"
[master (root-commit) 31ec8d9] release version
 1 file changed, 1 insertion(+)
 create mode 160000 AchaoCalculator

創建自己的存儲庫(略)

這時候執行上面兩條語句,git會提示403,也就是無權限訪問

因為git不知道你是誰,所以要給git一個公鑰,自己留個私鑰,具體配置看下面博客:

https://www.cnblogs.com/wmr95/p/7852832.html

之后提交就沒有問題了:

40184@Rongz MINGW32 /e/RongGit/AchaoCalculator (master)
$ git push -u origin master
Counting objects: 17, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (14/14), done.
Writing objects: 100% (17/17), 6.70 KiB | 190.00 KiB/s, done.
Total 17 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), done.
To github.com:Zrz458/ZrzCalculator.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.

總結

思路比代碼重要,思路不對累死狗,思路對了很簡單


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM