答題判題程式分析

Ccs星星远bird發表於2024-04-21

7-1設計一個風扇類
第一題是入門的一道題,首先定義一個風扇類(class Fan),包括常量(public final),不同型別的資料型別比如有int型別,boolean型別,double型別,string型別,然後一個無參構造方法,一個有參構造方法,把引數傳進去以獲得資料,最後用toString方法顯示物件(public String tiString())。
接下來是主函式的內容,需要注意的就是建立物件時new的用法(Fan fan1=new Fan();Fan fan2=new Fan(fanSpeed, fanOn,fanRadius,fanColor);)以及後續的引用,以及最後輸出時候用toString方法(System.out.println(fan2.toString());)。
7-2類和物件的使用
這道題比第一題進化一些,首先是有參構造方法用了this方法,然後是為屬性提供了getter()和setter()方法。
public String getName(){return name; } public void setName(String name){ this.name=name;}
7-3成績計算-1-類、陣列的基本運用
這道題又加入了一個點是在類裡面定義了sum和average方法去計算總分和平均分。
然後在主函式又新學了個知識就是建立物件陣列,因為學生有多個需要建立新的物件。
7-4成績計算-2-關聯類
這道題比上一題多加了東西但是基本還是一致的。

對答題判題程式的分析:
設計實現答題判題程式,這道題有三次變化,從最基本的框架開始,然後一步步去進化,每一次向其中加入更多的東西,比如一開始就是使用陣列,後面會用到arraylist類儲存資料,後面再學習HashMap的內容,然後下面就對這些題做一個逐步的分析。
7-1答題判題程式-1
首先每個基本的程式都是包括輸入和輸出的,那麼這個程式的輸入資訊就分為三部分,題目數量,題目內容,答題內容。
題目內容的輸入方式是有格式的,並且輸入的內容包括了題號,題目內容,標準答案,那麼就需要建立一個題目類class Lesson用於封裝單個題目資訊,然後它是一張試卷有多個題目,就需要試卷類class Term封裝整套題目的資訊,最後一個答題類去輸入答案,再將輸入的答案與標準答案比對看是否正確。
首先遇到的問題是不知道怎麼在試卷類裡面放多個題目,如何實現可以輸入多個,那麼就有了集合的內容,在試卷類中寫入題目類private Lesson lesson,再構造一個方法建立題目類的物件。而在答案類裡面就要實現答案和標準答案的比對,相同輸出true,不同輸出false。
然後這道題目最大的問題就是輸入的內容如何對應相應的部分,比如說如何獲得輸入的這部分內容是題目還是答案,如何將答案與標準答案比對。此時就會用到split方法,我們輸入一條字串,然後用正規表示式將輸入的題目分為題號,題目內容,標準答案三部分再呼叫term中的creat方法去建立物件。答案則是用了substring方法,取第三個之後的字元也就是輸入的答案與標準答案對比,然後用equals方法,遇到end時停止輸入,最後輸出。

7-2答題判題程式-2和7-3答題程式-3
在答題判題程-1的基礎上,增加了試卷資訊,裡面包含了試卷中不同題目的分值,答案也不知是單純一張卷子中,而是多張試卷,每組答案有試卷號,順序題號的各題目答案。

而答題判題程式-2和7-3答題程式-3的區別就在於後者又加入了學生資訊以及刪除題目資訊的功能,因為二者在答題時我的基本框架是一樣的,在這裡就一起分析。
首先,因為輸入變多了,複雜度也增高了,在方法上做了一些調整。輸入上一次性輸完所有的字串,然後在使用字串分割的方法把其分割成對應的部分,這是最開始的一個思路,具體實現會在後續解釋。
下面我就分析一下整個題目答題的類和具體內容分析。
1.Question 類:代表單個考試題目。
• id : 題目的序號。
• content : 題目內容。
• answer : 正確答案。
• valid : 題目是否有效,預設其值為 true。
在Question類中包含的方法:
因為題目中有無效性的測試,當輸入格式不對或者是錯誤引用了不存在的題號的試題時,這道題就是無效的,那麼在類中就寫入一個方法標記題目無效。
• invalidate() : 將題目標記為無效。
2. TestPaper 類:代表一份試卷,可以包含多個題目及其分值。
• id : 試卷的編號。
• questions : 一個有序的雜湊表,鍵是題目的 ID,值是該題目的分值。
從這裡開始,就學習了一個新的知識點,就是HashMap,HashMap是Map介面的一個實現類(HashMap實現了Map的介面),它具有Map的特點,HashMap的底層是雜湊表結構。Map具有雙列儲存的特點,一次新增兩個元素,也就是鍵值對。Key資料型別為Integer型別,Value資料型別為String型別的Map。
然後我對HashMap的方法做了一個總結。
① put方法:用於新增元素(定位到位置,其中無元素,直接插入)。
② get方法:get(object key)返回鍵對應的值。
③ remove方法:移除指定鍵值對。
④ getOrDefault方法:是Map提供的,對不存在的鍵值提供預設值的方法。
⑤ containsKey方法:判斷鍵(key)是否存在。
⑥ containsValue方法:檢查HashMap中是否有指定值。
⑦ computeIfAbsent方法:返回value值
⑧ size方法:返回鍵值對數量。

• 方法:
• addQuestion(int questionId, int points) : 向試卷新增題目以及其分值。
• totalPoints() : 計算試卷的總分。
這裡就會遇到一個問題,如何計算總分最為簡便,我不可能一個一個提取出來然後又相加,然後就查到了map中的一個方法去計算總分,就是map.values().stream().mapToInt(Integer::intValue).sum()。

  1. Submission 類 :表示學生對特定試卷的一次提交。
    • paperId : 提交對應的試卷 ID。
    • answers : 儲存學生提交的答案,鍵是題目序號,值是學生的答案。
    • 方法:
    • addAnswer(int questionSequence, String answer) : 新增學生的答案。
    • getAnswer(int questionSequence) : 獲取學生對某個題目的答案,如果未回答則返回 “answer is null”。
    4. Student 類 - 表示學生。
    • id : 學生的學號。
    • name : 學生的姓名。
    • submissions : 儲存學生的所有提交,鍵是試卷 ID,值是提交物件。
    • 方法:
    • ensureSubmission(int paperId) : 確保學生有一個對應的提交物件,如果沒有則建立一個。
    主函式:
    • questions : 儲存所有題目,鍵是題目 ID,值是 Question 物件。
    • testPapers : 儲存所有試卷,鍵是試卷 ID,值是 TestPaper 物件。
    • students : 儲存所有學生,鍵是學生 ID,值是 Student 物件。
    • errors : 儲存輸入解析過程中的錯誤資訊。
    • scanner : 用於讀取輸入資料。
    接下來就是主函式的編寫,主要思路還是輸入一串長字串然後對其進行處理將其分為各不同的題目,試卷封裝,學生資訊,答卷資訊,刪除的題目資訊比對後輸出對應內容。
    主函式:
    首先需要用private static final Map建立全域性變數,也是運用HashMap的內容。
    private static final Map<Integer, Question> questions = new HashMap<>();
    private static final Map<Integer, TestPaper> testPapers = new HashMap<>();
    private static final Map<String, Student> students = new HashMap<>();
    private static final List errors = new ArrayList<>();
    那麼如何把長字串分割呢,只需要在不同方法中實現,首先,因為它的輸入可能是亂序的,所以就需要有標誌判斷輸入的是什麼內容,這裡就會用到startsWith(“”)方法:用於檢查一個字串是否以指定的子字串開頭。
    比如說輸入字串line,則當line.startsWith("#N:")時就進行某種方法,然後這個迴圈是有條件的,就有了一個新的知識點,做了一個總結。
    ① next():遇到空格停止。
    ② nextLine:可輸入空格。
    ③ hasNext():檢查下一個標記,逐個讀取。
    ④ hasNextLine():檢查下一行是否存在,逐行讀取。
    注:每組元素個數確認或者已知時用in.hasNext(),每組元素個數不確定時用逐行讀取的in.hasNextLine()。
    在輸入時,用trim()方法去除空格,然後讀取到end就停止。

parseInput() : 解析輸入資料,根據不同的字首處理資料並儲存到相應的資料結構中。支援的字首包括:
• #N: : 解析題目:parseQuestion(line):利用split方法將輸入的題目根據空格分為幾部分,先檢查輸入格式,然後這裡用到了Integer.parseInt()方法是強制型別轉換,將字元型轉變成int型別以便序號比對,還有substring方法,subString是Java提供的一種字串擷取方法,通常我們可以用引數來控制擷取的字串,這裡用到的就是比如說parts[1].substring(3)就是此時得到的字串從下標為3的位置開始擷取到最後的值。然後再採用HashMap中的put方法將鍵值對輸入到列表中,一個id對應題目也就是questions.put(id, new Question(id, content, answer))。
HashMap的優點就是鍵值對,每一個點只有一個值,然後放到列表裡,就能夠比對試卷的編號,題號,從而確認輸出的內容。
• #T: : 解析試卷:parseTestPaper(line):與上基本一致,然後它是根據“-”分割的。
• #X: : 解析學生資訊:parseStudents(line):同上,就是分割學生的資訊,分為學號,姓名,再利用put放進列表中。
• #S: : 解析學生提交:parseSubmission(line),返回true或者false,如果格式不對則輸出wrong format的內容
• #D:N- : 標記某個題目為無效。
• 若行不符合上述格式,則記錄錯誤資訊。
• printErrorsAndResults() : 列印所有的錯誤資訊和每個學生的考試結果。檢查每份試卷的總分是否為100分,計算每個學生的每次提交的得分。
在輸出中用到了Map.Entry,Map.Entry是Map的一個內部介面。Map提供了一些常用方法,如keySet()、entrySet()等方法,keySet()方法返回值是Map中key值的集合;entrySet()的返回值也是返回一個Set集合,此集合的型別為Map.Entry。Map.Entry是Map宣告的一個內部介面,此介面為泛型,定義為Entry<K,V>。它表示Map中的一個實體(一個key-value對)。介面中有getKey(),getValue方法。我們要使用Map.Entry遍歷Map組合,再利用arraylist的內容儲存資料最後按照格式輸出。


相關文章