題目集4~6的總結性Blog

陶成万發表於2024-11-21

前言:
在本階段的課程設計中,我參與了三次題目集的練習和程式設計任務。這些題目不僅涵蓋了從簡單到複雜的演算法和資料結構問題,還涉及了實際應用中常見的題目型別,包括選擇題、填空題、以及更具挑戰性的程式設計題。這些題目的難度逐步加大,不僅考察了基礎的語法和演算法知識,還需要我們深入理解題目背景,進行更加細緻的邏輯推理。

題目數量:

  1. 題目集一:大多數題目集中在資料結構與基本演算法的應用,如連結串列操作、陣列排序等,題量適中。整體難度偏基礎,主要考察程式語言的基本運用及基礎演算法的實現。
  2. 題目集二:難度相較上次有所提高,涉及了更多的邊界條件處理和複雜的資料結構應用,如二叉樹的深度遍歷、圖的廣度優先搜尋等。這一題集不僅考察了基礎演算法的掌握,還加強了對邊界情況的思考。
  3. 題目集三:難度逐步加大,特別是在涉及多執行緒、複雜資料解析以及多選題和填空題的處理時,難度明顯增加。部分題目要求我們透過自定義資料結構和演算法來最佳化效能,如使用雜湊表進行高效查詢等。
    透過這三次題目集的訓練,我對程式語言的掌握更加深入,尤其是在資料處理、演算法設計、以及程式除錯方面積累了寶貴的經驗。

設計與分析:
在此次部落格中,我將分析題目集四中題目答題判題程式-4和家居強電電路模擬程式-2

(1) 答題判題程式-4
題目要求:
這道題目的設計要求包括輸入題目資訊、試卷資訊、學生資訊、答卷資訊以及刪除題目資訊等,並根據標準答案判斷學生的答題結果。

程式碼分析
這道題目相對複雜,要求我們設計一個答題判題程式,模擬一個小型的測試系統,以下是我對程式設計及其原始碼的分析。
class Input {
private String inputData;

public Input() {}

public Input(String data) {
    this.inputData = data;
}

public int judgeInput() {
    if(inputData.matches("#N:\\d+\\s+#Q:[^#]*#A:.*") ||
            inputData.matches("#K:\\d+\\s+#Q:[^#]*#A:.*") ||
            inputData.matches("#Z:\\d+\\s+#Q:[^#]*#A:.*")) {
        return 1;
    } else if(inputData.matches("(#T:\\d+){1}(\\s+[0-9]+-[0-9]+){0,}\\s*")) {
        return 2;
    } else if(inputData.matches("(\\s*#S:\\s*){1}(\\d+\\s+\\d+\\s*){1}(\\s*#A:\\s*\\d+-[^#]*){0,}\\s*")) {
        return 3;
    } else if(inputData.matches("(\\s*#X:\\s*){1}(\\d+\\s+[^- ]+-){0,}(\\d+\\s+.+){1}\\s*")) {
        return 4;
    } else if(inputData.matches("\\s*#D:\\s*N-\\d+\\s*")) {
        return 5;
    } else if(inputData.contains("end")) {
        return 6;
    } else {
        return 0; // 輸入格式不合法
    }
}

// 獲得建立的試卷中的資訊
public int[] getPaper() {
    inputData = inputData.replaceAll("#T:", "").trim().replaceAll("-", " ");
    String[] inputTemp = inputData.split("\\s+");
    int[] inputNums = new int[inputTemp.length];

    for (int i = 0; i < inputTemp.length; i++) {
        inputNums[i] = Integer.parseInt(inputTemp[i]);
    }
    return inputNums;
}

// 獲得題目
public Problem getProblem() {
    String[] inputSegments;
    int num = 0;
    String question = "", answer = "";
    int kind = 0;

    if (inputData.contains("#N:")) kind = 0;
    else if (inputData.contains("#Z:")) kind = 1;
    else if (inputData.contains("#K:")) kind = 2;

    inputData = inputData.replaceAll("^#", "");
    inputSegments = inputData.split("#");

    for (String segment : inputSegments) {
        if (segment.contains("N:") || segment.contains("K:") || segment.contains("Z:")) {
            segment = segment.replaceAll("N:|K:|Z:", "").trim();
            num = Integer.parseInt(segment);
        } else if (segment.contains("Q:")) {
            question = segment.replaceAll("Q:", "").trim();
        } else if (segment.contains("A:")) {
            answer = segment.replaceAll("A:", "").trim();
        }
    }

    if (kind == 0) {
        return new Problem(num, question, answer);
    } else if (kind == 1) {
        return new ChoiceProblem(num, question, answer);
    } else {
        return new FillProblem(num, question, answer);
    }
}

// 獲取單次(單張試卷)的回答
public String[] getAnswer() {
    inputData = inputData.replaceAll("#S:", "").trim();
    String[] inputTemp = inputData.split("-|#A:");
    for (int i = 0; i < inputTemp.length; i++) {
        inputTemp[i] = inputTemp[i].trim();
    }
    return inputTemp;
}

// 獲得學生資訊(學號、姓名)
public String[] getStudent() {
    inputData = inputData.replaceAll("#X:", "").replaceAll("-", " ").trim();
    return inputData.split("\\s+");
}

// 獲得刪除的題號
public int getDelete() {
    inputData = inputData.replaceAll("#D:", "").replaceAll("N-", "").trim();
    return Integer.parseInt(inputData);
}

public String getInput() {
    return inputData;
}

public void setInput(String input) {
    this.inputData = input;
}

}
在上述程式碼中,我們透過getProblem() 函式來解析輸入的題目資訊,並儲存題目的編號、內容及標準答案。使用字典結構方便後續查詢和處理。

資料結構選擇與設計
題目資訊(questions):選擇字典來儲存題目資訊是因為題目的編號是唯一的,字典的查詢時間複雜度為O(1),能夠快速匹配。
學生資訊(students):學生資訊以學號為鍵,姓名為值的方式儲存,便於查詢學生成績。

複雜度分析
透過對程式碼的逐步分析,題目要求的基本功能包括:
1.解析題目資訊
2.解析試卷資訊
3.判題和評分
4.處理刪除題目的資訊
時間複雜度:
解析題目資訊和試卷資訊的時間複雜度為O(n),其中n為題目和試卷的數量。
判題時,需要逐一比較答案,因此時間複雜度為O(m),其中m為學生答題的數量。

採坑心得:
在開發過程中,我遇到了幾個重要問題,需要總結和分享這些“採坑”心得:
問題:輸入順序不一致
o題目資訊、試卷資訊、學生資訊以及答卷資訊的輸入順序不固定。雖然題目要求保證輸入格式正確,但順序不一致會導致程式碼在解析資料時容易出錯,尤其是在處理試卷編號和題目編號時。
o解決方案:透過優先解析“#T:”行中的試卷資訊,再根據題目編號匹配相關的答案。使用字典儲存題目資訊,能夠讓我們根據題目編號快速查詢到對應的答案。

問題:題目刪除功能的實現
o刪除題目時,原本的題目資訊並不被清除,而是顯示為“無效”或“0分”。這在實現時需要特別注意,尤其是在答卷評分時,如何識別和處理被刪除的題目。
o解決方案:在判題時,如果發現題目已被刪除,則直接判為無效並給0分。

問題:部分答案正確的處理
o多選題和填空題需要判定部分正確的情況。處理此類題目時,首先要判斷答案是否包含所有正確項,然後計算部分得分。
o解決方案:對於多選題,我採用了將標準答案和學生答案轉化為集合進行比較的方法,判斷是否完全正確或部分正確。

改進建議:
在編寫答題判題程式時,我認為以下幾點可以進一步改進:
增強輸入資料驗證
o目前的程式沒有對輸入資料進行充分的驗證,可能會導致非法資料(如格式錯誤、無效題目編號等)導致程式崩潰。可以透過正規表示式增強輸入的驗證,確保資料格式正確。
最佳化部分答案的判定邏輯
o對於部分答案的處理,當前程式碼中採用的方式較為簡陋,可以考慮引入更復雜的評分演算法。例如,在多選題中,判斷學生是否選對了所有正確答案,並根據選錯答案的數量進行扣分。
改進介面設計
o目前的程式僅透過命令列輸出結果,如果能夠提供一個圖形化介面(GUI)來展示學生的答題情況和評分,將大大提升使用者體驗,尤其是在處理多道題目時,能夠更直觀地檢視學生的表現。

(2) 家居強電電路模擬程式-2
題目要求:
設計一個簡單的電路模擬系統,要求能夠解析使用者輸入的電路配置資料,並能夠模擬電流、電壓的計算與動態變化,同時支援開關控制和元件狀態更新,最終展示電路的執行狀態。系統需要能夠支援簡單的串聯電路,並具備使用者互動功能。

類設計
CircuitDiagram 類
1.功能:負責電路圖的模擬與管理,計算電路中每個元件的電流與電壓,並實時更新電路狀態。
2.方法:
1.renew(): 更新電路中每個元件的狀態(電流、電壓)。
2.showInfo(): 輸出電路狀態資訊,幫助使用者檢視電路執行情況。

Input 類
1.功能:解析使用者輸入的電路配置,轉化為可操作的資料結構。
2.方法:
1.splitCircuit(): 根據輸入的電路資料,拆解出電路中各個元件。
2.judgeInput(): 驗證輸入資料的有效性,確保電路配置符合規則。

Controller 類
1.功能:負責管理電路的輸入與操作,控制電路的狀態變化。
2.方法:
1.inputCircuit(): 處理使用者輸入,構建電路模型。
2.operation(): 執行使用者的操作命令(如改變開關狀態、調節電壓等)。

設計分析

  1. 電路模擬核心
    系統透過計算電路中的電流與電壓來模擬實際電路的執行。每個元件(如電阻、開關)根據電流的大小調整電壓,renew() 方法完成這一核心計算,並動態更新電路狀態。

  2. 輸入解析與電路構建
    Input 類透過方法如 splitCircuit() 解析使用者輸入的電路配置(例如:Z27XC48VB31N1M4Q),將其轉換為電路元件,並使用 judgeInput() 驗證輸入的合法性。

  3. 元件控制與狀態更新
    系統支援使用者對電路元件的操作,如開關控制、調節電流和電壓等。透過呼叫 operation() 方法,使用者能夠實時控制電路狀態,而 showInfo() 方法則提供電路狀態的即時反饋。

  4. 電路連線與拓撲結構
    當前系統設計主要支援串聯電路,splitCircuit() 和 renew() 方法將電路元件按使用者輸入進行連線,並在電路變化時更新狀態。

  5. 擴充套件性與最佳化
    該設計可擴充套件以支援並聯電路或更復雜的電路拓撲。也可以加入更多的電路元件,如電容、電感等。效能最佳化方面,可以減少重複計算,提升大規模電路模擬的效率。

提交的原始碼分析

  1. 程式碼結構:程式碼按功能模組進行劃分,CircuitDiagram 類負責電路的核心模擬,Input 類負責解析與驗證使用者輸入,Controller 類負責互動控制,具有清晰的職責分離。
  2. 功能實現:透過 splitCircuit() 方法,程式碼能夠高效地將使用者輸入的資料轉化為電路元件。renew() 方法根據電流和電壓的變化動態更新電路狀態,確保模擬的準確性。
  3. 互動與反饋:系統能夠根據使用者輸入的電路配置實時展示電路的狀態變化,反饋機制簡潔明瞭,使用者可以直觀地看到電路的工作情況。

心得體會
透過這次電路模擬系統的設計與實現,我加深了對電路模擬與計算的理解,特別是電流與電壓的動態變化與控制。此外,在解析使用者輸入時,處理資料結構和驗證有效性是非常重要的步驟,這有助於避免錯誤輸入導致的系統崩潰。
我還認識到模組化設計的重要性,程式碼結構的清晰和模組之間的解耦使得整個系統易於擴充套件與維護。在實際開發中,如果沒有良好的類設計和資料結構規劃,後期維護和修改將變得困難。

採坑心得
輸入資料的處理
在解析輸入資料時,遇到過輸入格式不一致的問題,尤其是在不同格式的電路圖配置資料之間進行轉換時,格式驗證非常關鍵。judgeInput() 方法的設計幫助我避免了輸入不規範的資料對系統執行的影響。

效能問題
電路模擬過程中,當涉及到大量元件時,效能成為了瓶頸。特別是 renew() 方法每次都要遍歷整個電路進行計算,這在電路複雜度較高時導致了計算效率低下。對此,我考慮到未來可以透過引入快取機制或者最佳化計算公式來提升效能。

拓撲結構的支援
目前系統僅支援串聯電路,這意味著如果使用者輸入複雜的並聯電路配置,系統無法正確處理。為了提高系統的通用性,需要對電路拓撲的解析邏輯進行擴充套件,支援並聯和混合電路的處理。

改進建議
透過這次題目集的練習,我對程式碼設計提出了以下幾點改進建議:

  1. 增強效能
    對於電路模擬中的大量計算,可以透過最佳化計算方法或者引入快取機制來提升效能,特別是在電路較為複雜時,避免重複計算。
  2. 支援更復雜的電路拓撲
    當前系統僅支援串聯電路,建議擴充套件系統,支援並聯電路、混合電路等更多複雜電路拓撲的模擬。
  3. 模組化設計與複用性
    進一步提升程式碼的模組化程度,確保每個功能模組具有較高的複用性。可以將電路元件與控制邏輯解耦,使得不同電路元件可以根據需要靈活替換或擴充套件。
  4. 圖形介面
    目前的系統僅提供命令列輸入與反饋,建議未來新增圖形介面,使使用者能夠直觀地設計電路、檢視電路狀態並進行操作。這將極大提升使用者體驗,特別是在設計複雜電路時。
  5. 輸入格式與驗證
    輸入格式和驗證的處理是系統中至關重要的部分,建議在輸入資料解析時增加更多的格式檢查和容錯處理,確保使用者輸入時可以容忍一些常見的格式錯誤。

總結:對本階段三次題目集的綜合性總結
經過這三次題目集的練習,我收穫了很多寶貴的程式設計經驗和解決問題的技巧。每一次完成作業後,我都能感覺到自己對程式設計的理解和能力在不斷提升。特別是在處理複雜題目時,我能夠更加熟練地運用演算法和資料結構來解決問題。
學到了什麼:

  1. 如何在不確定輸入順序的情況下正確解析資料。
  2. 如何判斷部分答案正確,並根據不同情況給出不同的評分。
  3. 如何最佳化程式碼效能,使得複雜資料的處理更加高效。
  4. 對複雜演算法的最佳化,尤其是在處理大規模資料時,如何減少時間複雜度。
  5. 更深入地學習物件導向程式設計(OOP)和設計模式,在複雜的程式設計中應用這些思想。
  6. 課程內容上可以增加更多的實際應用案例,幫助我們理解如何將所學知識應用於真實的工程專案中。
  7. 對於作業和實驗,可以引導我們在解決問題時進行更多的思考和討論,提供更多的挑戰性題目。
    總之,這三次題目集的實踐讓我收穫頗豐,不僅提升了程式設計能力,還加深了對程式設計與演算法的理解,為今後的學習打下了堅實的基礎。

相關文章