一.前言
本學期新增JAVA的面向程式設計課程,為增加學生編寫能力開始了本學期的PTA作業,以及接下來我將根據我的實際情況總結前三次PTA題目集中最後一題並講訴自己對Java的學習心得。從這三次PTA作業中學習到的了對ArrayLis、Vector等自動增長的陣列的使用方法,學習到了許多Java自帶的方法如:split、size、contains等,並且經過這三次P他的磨練,我已經能夠相對熟練的使用正規表示式,並自己寫一些需要的正規表示式,透過使用正規表示式可以大幅度簡化對字串格式的判斷。
二.設計與分析
(1)第一次PTA最後一題如下:
7-5 答題判題程式-1
分數 74
困難
作者 蔡軻
單位 南昌航空大學
設計實現答題程式,模擬一個小型的測試,要求輸入題目資訊和答題資訊,根據輸入題目資訊中的標準答案判斷答題的結果。
本次題目主要透過輸入:題目數量、題目內容:輸入多行資料,每行代表一道題目。每行資料包含題號(#N:)、題目內容(#Q:)和標準答案(#A:)。題目的輸入順序與題號不相關,即題號可能不是按順序給出的、答題資訊:輸入多行資料,每行代表一組答案。每行資料包含多個答案,答案之間用英文空格分隔,順序與題目題號相對應。答題資訊以一行"end"結束,"end"之後的資訊將被忽略。所以需要讀取到主要的題目數量,並根據題目數量建立問題陣列、答案陣列,分別用於儲存問題資訊、答案資訊後對答案和問題的標準答案進行比較給出輸出結果。
因為題目最後給出了設計建議,所以就按照設計建議寫了類,類圖如下:
其中,Program類用於儲存單個題目資訊,Exam類用於將所有的問題類存起來,answer類用於存放答卷的答案資訊。為了便於查詢題號、比較題目的標準答案以及在輸出時輸出題目,我寫了一個工具類Getstring來拆分得到的字串。程式碼如下:
點選檢視程式碼
class Getstring {
public static String getstring(String programs,String a,String b) {
int start = programs.indexOf(a)+3;
int end = programs.indexOf(b)-1;
return programs.substring(start,end);
}
}
點選檢視程式碼
public static String[] sort(String[] a) {
for(int i=0;i<a.length;i++) {
for(int j=i+1; j<a.length;j++) {
if(Integer.parseInt(Getstring.getstring(a[i],"#N:","#Q:").trim())>Integer.parseInt(Getstring.getstring(a[j],"#N:","#Q:").trim())) {
String t = a[i];
a[i] = a[j];
a[j] = t;
}
}
}
return a;
}
心得:
本次作業難點在於:1.題目數量、題目內容和答題資訊的輸入和解析。2.根據標準答案判斷答題結果。3.輸出格式的控制,確保題目內容和答案正確對齊。
由於是第一次大作業,所以可想而知這次是挺簡單的(也是唯一覺得簡單的一次),沒有太過複雜的操作和***鑽的測試點。提交程式碼後主要錯誤集中在格式錯誤,沒有考慮到有多個答案時,最後輸出的true和false中間要加空格。在圓滿完成Java程式設計的初次作業後,我深切感受到了自己對Java這門語言的認知邁上了一個新臺階。這次實踐不僅深化了我對類單一職責原則的理解,還讓我對類的應用有了更為透徹的把握。
在作業完成的過程中,我也遭遇了不小的挑戰,特別是在除錯程式碼和理解作業要求方面。然而,正是這些困難成為了我成長的催化劑。我透過廣泛查閱資料、積極向同學求教,以及無數次的嘗試與修正,最終成功地跨越了這些障礙,圓滿完成了作業。
作業雖已告捷,但我深知自己在程式設計技能和邏輯思維方面仍有諸多不足。因此,我決心在接下來的學習旅程中,加大對Java程式設計實踐的投入力度。我將透過多做程式設計練習,自主探索一些富有挑戰性的實際專案,來不斷錘鍊自己的程式設計技藝。我堅信,只要持之以恆地努力和實踐,我必定能在Java程式設計的廣闊天地中取得更加輝煌的成就。
這次作業不僅讓我體驗到了程式設計帶來的無窮樂趣和重重挑戰,更點燃了我對Java程式設計的濃厚興趣。我滿懷期待地憧憬著未來,渴望學習更多關於Java程式設計的精髓,探索更多令人著迷的程式設計問題,不斷攀登程式設計技藝的新高峰。
(1)第二次PTA最後一題如下:
7-2 答題判題程式-2
分數 54
困難
作者 蔡軻
單位 南昌航空大學
設計實現答題程式,模擬一個小型的測試,以下粗體字顯示的是在答題判題程式-1基礎上增補或者修改的內容。
要求輸入題目資訊、試卷資訊和答題資訊,根據輸入題目資訊中的標準答案判斷答題的結果。
此次作業在第一次作業的基礎上進行了難度的提升。不再給出問題數量,並且多了試卷資訊,答案順序也根據試卷資訊的順序給出。所以本次用不了靜態陣列。只能選擇動態陣列了。並且試卷類跟答卷類也多了有關於順序的聯絡。最後對順序匹配的答案和問題的標準答案進行比較給出輸出結果。
類圖如下:
因為本次多了試卷資訊,所以也是重寫了Exam類,使它專用於存放試卷資訊和題目對應的分數,至於多個問題資訊則直接使用動態陣列Vector。然後再Exam、Answer類中多加了屬性num用於對應試卷號和答卷號。
因老師在課上說了不要在main中放太多操作,所以在本次迭代中,我增加了一個Student類替代之前的工具類Getstring,並放入所有的輸入、輸出等操作。又因為這次作業在輸入時不再提供問題數量,只能選擇動態陣列儲存問題、答卷、試卷資訊。查閱資料後使用 Vector ,Vector 可以根據新增或刪除元素的需求自動調整其大小。這避免了像靜態陣列那樣需要手動管理陣列大小和複製陣列內容的問題。程式碼如下:
點選檢視程式碼
static Vector<Program> program = new Vector<>();
static Vector<Answer> answer = new Vector<>();
static Vector<Exam> test = new Vector<>();
點選檢視程式碼
public void setAll(String s) {
String[] str = s.trim().replace("#T:","").split("[^0-9]");
grade = new int[(str.length-1)/2];
testno = new int[(str.length-1)/2];
no = Integer.parseInt(str[0]);
for(int i=1; i<str.length; i+=2) {
this.testno[(i-1)/2] = Integer.parseInt(str[i]);
}
for(int i=2; i<str.length; i+=2) {
this.grade[(i-1)/2] = Integer.parseInt(str[i]);
}
}
點選檢視程式碼
public boolean jutice(Program a,String s) {
if(a.getStandard().equals(s))
return true;
return false;
}
點選檢視程式碼
if(s.indexOf("#N") != -1) {
a.setAll(s);
program.add(a);
}
心得:
本次作業難點在於:1.試卷資訊和答卷資訊的解析和匹配。2.試卷總分的計算和警示資訊的輸出。3.答卷資訊和判分資訊的輸出格式控制。
此次才第二次大作業,我已經在本次作業中感受到了難度,特別是在迭代過程中對類的劃分不清晰,寫著寫著就容易忘記每個類的作用。但好在本次沒有太過***鑽的測試點。提交程式碼後雖然錯了幾次,但根據測試點的提示資訊還是解決了輸入答案為空的問題。
在檢查輸入的語句屬於問題、試卷還是答卷時,我使用了indexOf方法。但在後來發現還有更好的判斷字串是否有指定子串的方法:contains。contains只返回true、false更適用與字串和子串的匹配。另外在本次PTA中也是在split方法中使用了一點點的正規表示式,讓我感受到了正規表示式的便利。
最後透過把各個功能劃分到不同類中,提高了程式碼的可閱讀性和可維護性。本次作業也讓我感受到了Java的難度,特別是劃分類之後,程式碼量一下就上來了。
(1)第三次PTA最後一題如下:
7-3 答題判題程式-3
分數 80
困難
作者 蔡軻
單位 南昌航空大學
設計實現答題程式,模擬一個小型的測試,以下粗體字顯示的是在答題判題程式-2基礎上增補或者修改的內容,要求輸入題目資訊、試卷資訊、答題資訊、學生資訊、刪除題目資訊,根據輸入題目資訊中的標準答案判斷答題的結果。
此次作業難度再一次加大,除之前的問題、試卷、答卷資訊外,增加了學生資訊和刪除題目資訊。所以在輸入時要增加匹配,並且由於多了刪除題目資訊和試卷中不一定會出現所有題目,所以在題目類中增加了兩個屬性:exist、Examexit。用於判斷該題是否在試卷中出現及是否被刪除題目資訊刪除掉。
類圖如下:
因為問題多了兩個屬性,所以重寫了Answer類中的justice方法。程式碼如下:
點選檢視程式碼
public boolean jutice(Program a,String s) {
if(a.getExist()&&a.getStandard().equals(s)&&a.getExamexit())
return true;
else if(!a.getExist()&&a.getExamexit())
System.out.println(String.format("the question %d invalid~0",a.getNo()));
else if(!a.getExamexit()&&!a.getExist())
System.out.println("non-existent question~0");
return false;
}
點選檢視程式碼
public void setAnswer(String m) {
answer = Arrays.copyOf(answer, answer.length+1);
answer[answer.length-1] = m;
}
public void setAnswerid(int id) {
answerid = Arrays.copyOf(answerid, answerid.length+1);
answerid[answerid.length-1] = id;
}
點選檢視程式碼
public void juiceExist(Vector<Program> program) {
//temp用於判斷在當前試卷中該題目是否出現
boolean temp = false;
for (Program pro : program) {
for (int isExit : this.getTestno()) {
if (pro.getNo() == isExit) {
pro.setExamexit(true);
temp = true;
break;
}
}
if (!temp) {
pro.setExamexit(false);
}
temp = false;
}
}
點選檢視程式碼
boolean temp1 = false, temp2 = false;
for (Program pro : program) {
if (exam.getTestno()[i] == pro.getNo()) {
temp1 = true;
if (ans.getAnswerid() != null) {
for (j = 0; j < ans.getAnswerid().length; j++) {
if (i + 1 == ans.getAnswerid()[j]) {
temp2 = true;
break;
}
}
if (temp2) {//答卷中有該問題
if (ans.jutice(pro, ans.getAnswer()[j]))
a[k] = exam.getGrade()[i];
if (pro.getExist() && pro.getExamexit())
System.out.println(pro.getContent() + "~" + ans.getAnswer()[j] + "~" + ans.jutice(pro, ans.getAnswer()[j]));
k++;
break;
}
}
if (!temp2) {
System.out.println("answer is null");
}
}
}
if (!temp1)
System.out.println("non-existent question~0");
心得:
本次作業難點在於:1.學生資訊和答卷資訊的匹配。2.刪除題目資訊的處理,確保被刪除題目在輸出時給出提示。3.各種錯誤提示資訊的輸出,包括格式錯誤、試卷號引用錯誤、學號引用錯誤等。
此次已經是第三次作業了,在本次作業中,我切實感受到了來著題目的深深的惡意,各種不同情況對應的輸出不同。除此之外,對刪除掉的問題的輸出也和其他情況不同。這些不同的情況還對應這不同的優先順序,這讓我需要不斷調整輸出的位置。透過把各個功能劃分到類中和類的劃分讓我節省了許多精力,也提升了程式碼的可閱讀性。在修改錯誤時也能快速定位到具體位置上。其次也簡化了程式碼。這讓我感受到物件導向程式設計的便利。
在這三次作業中我深深的感受到物件導向程式設計的好處,比如程式碼更容易迭代,在後續修改程式碼時,只需要在原本的基礎上調整一小部分,不像c語言,程式碼很難複用。
三.踩坑心得
對於這三次PTA作業,踩過最大的肯那必然是提交、測試之後出現非零返回,如第二次和第三次P他的:
非零返回真是讓人要吐了,其中主要出現這個問題的原因在於定義陣列之後沒有對陣列進行初始化,或者是陣列越界。每次出現非零返回時認真檢視一下定義和使用陣列的地方就能找出問題所在。此外,還有輸入中含有空格、空的情況也容易導致引起陣列的越界或賦空值。所以每次都要測試一下輸入空值或空格的情況,除這兩個最讓人頭疼的問題外,還有就是格式錯誤,在輸出的時候容易忘記空格或多加空格。比如:
簡單修改後就能解決。
四.改進建議
對於這三次的PTA作業我覺得可以把程式碼中比較的部分細分出一些小的方法,另外可以考慮使用 ArrayList 代替 Vector,因為 ArrayList 在大多數情況下效能更好,且執行緒安全性不是這裡的關鍵需求。類和方法的命名應該更具描述性。例如,input 方法可以命名為 readInput,output 方法可以命名為 printResults。最佳化輸出格式,使其更加清晰易讀。
五.總結
透過這三次PTA作業,我逐步實現了一個功能完善的答題判題程式。從最初的簡單輸入輸出,到後來的試卷和答卷處理,再到最後的學生資訊和刪除題目處理,每一次作業都增加了新的功能和挑戰。透過不斷除錯和最佳化,我逐漸掌握瞭如何使用字典和列表儲存和查詢資訊,如何處理複雜的輸入和輸出格式,以及如何增加錯誤檢測和處理來提高程式的健壯性。這些經驗對我未來的程式設計學習和實踐將非常有幫助。