用C#寫綜合實驗的一些感想和收穫

經過這周學校的綜合實驗,本身寫的程序終於從之前的黑框框變成了一個真正能讓人看的程序。因爲有必定的基礎,因此並不會感到很是的難,如下是我遇到的一些相對比較棘手的問題。算法

1、使用棧實現計算器優先級

計算器四則運算優先級老師要用棧去實現,就去翻了翻數據結構書,思路大概以下:
所包含的運算符有‘+’,‘-’,‘*’,‘/’, 表達式爲字符串。數組

(1)創建兩個棧,一個用來存儲操做數,另外一個用來存儲運算符, 開始時在運算符棧中先壓入‘/0’,表達式的結束符。數據結構

clipboard.png

(2)而後從左至右依次讀取表達式中的各個符號(操做數或者運算符);工具

(3)若是讀到的是操做數直接存入操做數棧;google

(4)若是讀到的是運算符,則做進一步判斷:spa

若讀到的運算符的優先級等於或小於以前的運算符的優先級,則從操做數中退出2個,從運算符中退出一個進行運算,將運算結果存入操做數棧;再把以前讀到的運算符與目前的運算符棧頂比較,重複步驟(4)(即如今不讀下一個元素);code

clipboard.png

clipboard.png

clipboard.png

若讀到的是‘/0’結束符,並且此時運算符棧的棧頂元素也是‘/0’結束符,則運算結束,輸出操做數棧中的元素即爲最後結果。orm

// 進行運算
    private double Calculate(string operators, string numbers) {
        // 將數字和操做符字符串存到數組當中
        string[] numberarray = Regex.Split(numbers, " ");
        string[] operatorarray = Regex.Split(operators, " ");
        Stack numberStack = new Stack();// 數字棧
        Stack operatorStack = new Stack();// 操做符棧

        // 先將前兩個數字和一個操做符push到棧中
        numberStack.Push(Convert.ToDouble(numberarray[0]));
        numberStack.Push(Convert.ToDouble(numberarray[1]));
        operatorStack.Push(operatorarray[0]);
        
        // 當遍歷完操做符數組且棧中操做符爲空時跳出循環
        for (int i = 1; i < operatorarray.Length || !operatorStack.IsEmpty();) {
            // 當操做符棧爲空時,push一個數字和一個操做符
            if (operatorStack.IsEmpty()) {
                numberStack.Push(Convert.ToDouble(numberarray[i + 1]));
                operatorStack.Push(operatorarray[i]);
                i++;continue;
            }
            // 當棧頂操做符爲+或者-時
            if (operatorStack.getTop().Equals("+") || operatorStack.getTop().Equals("-")) {
                if (i < operatorarray.Length) { // 當下一個操做符不是最後一個操做符時
                    // 若是下一個操做符爲*或者/,則push一個數字和操做符
                    if (operatorarray[i].Equals("*") || operatorarray[i].Equals("/")) {
                        numberStack.Push(Convert.ToDouble(numberarray[i + 1]));
                        operatorStack.Push(operatorarray[i]);
                        i++;
                    } else {// 不然,棧內進行加減運算,將結果push到棧頂,下同
                        double after = Convert.ToDouble(numberStack.Pop());
                        double pre = Convert.ToDouble(numberStack.Pop());
                        string op = operatorStack.Pop().ToString();
                        switch (op) {
                            case "+": { numberStack.Push(pre + after); continue; }
                            case "-": { numberStack.Push(pre - after); continue; }
                            default: continue;
                        }
                    }
                } else {// 若是沒有下一個操做符,則棧內進行加減運算
                    double after = Convert.ToDouble(numberStack.Pop());
                    double pre = Convert.ToDouble(numberStack.Pop());
                    string op = operatorStack.Pop().ToString();
                    switch (op) {
                        case "+": { numberStack.Push(pre + after); continue; }
                        case "-": { numberStack.Push(pre - after); continue; }
                        default: continue;
                    }
                }
            } else {// 若是棧頂操做符爲*或者/,則棧內直接進行乘除運算
                double after = Convert.ToDouble(numberStack.Pop());
                double pre = Convert.ToDouble(numberStack.Pop());
                string op = operatorStack.Pop().ToString();
                switch (op) {
                    case "*": { numberStack.Push(pre * after); continue; }
                    case "/": { numberStack.Push(pre / after); continue; }
                    default: continue;
                }
            }
        }
        // 取出棧頂元素做爲結果返回
        object result = numberStack.Pop();
        return Convert.ToDouble(result);
    }

2、通信錄管理的編輯功能

編輯功能一開始沒什麼太好的方法,就用了一個比較「猥瑣」的方式:ip

  1. 先選中要編輯的一行->
  2. 將這一行的數據傳遞給編輯窗口->
  3. 刪除這一行的數據。

而編輯窗口本質就是一個自帶默認數據的增長窗口。資源

// 點擊編輯按鈕 
 private void EditButton_Click(object sender, EventArgs e) {
        // 若是有被選中的項
        if (listView1.SelectedItems.Count != 0) {
            // 將選中行的信息封裝到person中
            Person editPerson = new Person {
                Id = listView1.SelectedItems[0].SubItems[0].Text,
                Name = listView1.SelectedItems[0].SubItems[1].Text,
                Sex = listView1.SelectedItems[0].SubItems[2].Text,
                WorkPlace = listView1.SelectedItems[0].SubItems[3].Text,
                Phone = listView1.SelectedItems[0].SubItems[4].Text,
                Email = listView1.SelectedItems[0].SubItems[5].Text
            };

            // 打開編輯窗口,將person傳入
            editForm = new Edit(editPerson);
            editForm.Show();
            
            // 刪除選中行的信息
            DeleteSelectCol();

            // 從新加載數據
            Display();
        }
    }

clipboard.png
而接下來就出現問題了,以下圖,編輯窗口的任務並無結束,但表格已經把選中的信息給刪了。

clipboard.png

後來我去google,簡單的瞭解到這是因爲我啓動編輯窗口時以show()的方式啓動,而show是非模態顯示,另外一個和它功能相近的方法是showDialog()模態顯示,兩者區別是:
模態顯示後:

  1. 彈出窗口阻止調用窗口的全部消息響應。
  2. 只有在彈出窗口結束後調用窗口才能繼續。
  3. 在模態窗口「關閉」後,能夠讀取模態窗口中信息,包括窗口的返回狀態,窗口子控件的值

非模態顯示後:

  1. 能夠在彈出窗口和調用窗口之間隨意切換。
  2. 調用窗口調用show方法後,下面的代碼能夠當即執行
  3. 在非模態窗口關閉後,窗口的全部資源被釋放,窗口不存在,沒法獲取窗口的任何信息。

因此當我用show()顯示編輯時,下面的DeleteSelectCol()方法會當即執行。
因此,最後我改用showDialog()來顯示編輯窗口,當點擊保存時,窗口狀態返回OK,而且將DeleteSelectCol()的條件改成窗口返回狀態。
最後改寫的代碼以下:

clipboard.png

clipboard.png

總結

  1. 學好數據結構很重要,有了核心的算法,代碼只是實現的工具。
  2. 因爲以前寫項目時常常遇到增刪改查,因此寫通信錄管理時感受很是輕鬆,思想有了,無論用什麼語言上手都很快。
相關文章
相關標籤/搜索