前言
本次的總結是關於第四、五、六次pta程式設計作業的概括與分析,也是對自己近一個月java學習方面上的成
果收穫與經驗教訓的回顧與反思。
-
對於知識點的總結
第四次的作業主要還是在前三次的程式上進行迭代並新增了新的類來處理不同的資料,這也是主要的新的難點。在這次的作業中,我對正規表示式的功能與便捷有了更深的體會。其實有些題目的難點並不是類間設計的難點,而是如何合理的對輸入的資料進行恰當的處理。而透過正規表示式則可以極大地便利我們。第五次的作業改變為了新的題型——家居電路模擬題,是使用程式碼將不同的電器透過串聯或並聯的方式連線起來形成迴路並能夠透過改變電路中的電器的狀態來實現對電器的控制。第六次作業則是在這基礎上進行迭代。這兩道題中都涉及到對繼承和多型的反覆使用,並且透過對集合的合理使用能夠大大降低資料處理的難度,例如HashMap,ArrayList等。
-
對於體量與難度的說明
綜合來講,總體題量不是特別大,但對於我來說短時間內完成還是非常困難,而我也主要將時間花費在了對類間關係的設計與除錯上,這些也佔用了我的大部分時間。在我看來,這些pta的題目對於我這樣語文不是太好的人來說難度更是直線飆升,在每次新的作業釋出後我都需要花費幾個小時來將文字極多的題幹、設計需求、類間關係、輸入輸出樣例來反覆斟酌才能理解其中的原理並加以設計程式,這也是我花費時間多的原因之一。但在對原理理解通透之後,再來編寫程式便可快速上手。還有其他的難點就是對於資料的處理,但經過前幾次作業的磨鍊後也沒花費過多的時間也解決了。
-
設計與分析
第四次作業:
資料處理過程是我認為難度最大的一步,所以我把關於資料處理方面的原始碼展示出來:Scanner scanner = new Scanner(System.in); HashMap<Integer, String> questionMap = new HashMap<>(); HashMap<Integer, HashMap<Integer, Integer>> quotaMap = new HashMap<>(); HashMap<Integer, String> studentMap = new HashMap<>(); HashMap<String, HashMap<Integer, String>> answerMap = new HashMap<>(); HashSet<Integer> deletedQuestionSet = new HashSet<>(); boolean isFirstStudent = true; boolean isFirstTestPaper = true; int maxScore = 0; while (scanner.hasNextLine()) { String line = scanner.nextLine().trim(); if (line.equals("end")) { break; } if (line.startsWith("#N:")) { parseQuestionInfo(line, questionMap); } else if (line.startsWith("#T:")) { parseTestPaper(line, quotaMap, questionMap); isFirstTestPaper = false; } else if (line.startsWith("#X:")) { if (!isFirstStudent) { printScoreInfo(answerMap, studentMap, quotaMap, deletedQuestionSet, maxScore); resetMaps(questionMap, answerMap, deletedQuestionSet); maxScore = 0; } parseStudentInfo(line, studentMap); isFirstStudent = false; } else if (line.startsWith("#S:")) { parseAnswerInfo(line, answerMap, quotaMap, deletedQuestionSet); } else if (line.startsWith("#D:")) { parseDeletedQuestion(line, deletedQuestionSet); } } printScoreInfo(answerMap, studentMap, quotaMap, deletedQuestionSet, maxScore);
}
透過每個類開頭的不同資訊來將其透過正規表示式分割為單個的字串,並將每個字串存入與其對應的集合中,以便在後續使用中對其中的資料進行處理。在這次作業中我也將原來使用的ArratList集合改換為了HashMap集合,因為Map類集合可以儲存兩個資料,如果將題目對應的題號儲存在鍵物件中且題目的內容或是資料儲存在值物件中,會大大提高程式碼執行效率且更為簡潔。
第五次作業:
類圖:
需求
需要將受控裝置——包括白熾燈、日光燈和吊扇,而且每個裝置在不同的電壓下會存在不同的狀態,在對搜空裝置檔位的調節中可以改變為不同的狀態。而控制裝置則包括:開關、連續調速器和風檔調速器,這其中的開關能夠控制電路是否有電,而兩個調速器則是用來改變輸入輸出的電壓值。
分析
這次為新的題型,但總體的設計思路與之前的作業相比並無太大的差別,依然是考察我們對於類間設計和資料處理的能力,但第一道題對於資料量較少,所以並不複雜,難的是全新的類間關係,這也需要一點小小的電學知識,但好在這題只需要最簡單的串聯電路將幾個用電器連線起來就好。但新的考察點也有了繼承與抽象類的知識,這需要其中的受控裝置、控制裝置、串聯電路都需直接繼承於電路裝置類。
第六次作業:
家居電路模擬系列所有題目的預設規則:
1、當計算電壓值等數值的過程中,最終結果出現小數時,用截尾規則去掉小數部分,只保留整數部分。為避免精度的誤差,所有有可能出現小數的數值用double型別儲存並計算,不要作下轉型資料型別轉換,例如電壓、轉速、亮度等,只有在最後輸出時再把計算結果按截尾規則,捨棄尾數,保留整數輸出。
2、所有連線資訊按電路從電源到接地的順序依次輸入,不會出現錯位的情況。
3、連線資訊如果只包含兩個引腳,靠電源端的引腳在前,靠接地端的在後。
4、對於調速器,其輸入端只會直連VCC,不會接其他裝置。整個電路中最多隻有一個調速器,且連線在電源上。
家居電路模擬系列1-4題目後續迭代設計:
1、電路結構變化:
迭代1:只有一條線路,所有元件串聯
迭代2:線路中包含一個並聯電路
迭代3:線路中包含多個串聯起來的並聯電路
迭代4:並聯電路之間可能出現包含關係
類圖:
需求
第六次的作業是在上一次的基礎上增加了並聯電路類和一個受控裝置,並且在電路裝置的基礎上增加了電阻這個屬性,這其中的關鍵點是一條由多個裝置組成的串聯電路或並聯電路也可以看做一個獨立的串聯裝置。
分析
這兩個電路類中最難的點是對每條電路的儲存,並且必須保證在這同時還能實現電路的動態變化,程式碼如下:
class Circuit {
Map<String, Device> devices = new HashMap<>();
List<List<String>> connections = new ArrayList<>();
void addDevice(Device device) {
devices.put(device.id, device);
}
Device getDeviceById(String id) {
return devices.get(id);
}
void addConnection(List<String> connection) {
connections.add(connection);
}
void applyVoltage(String startDeviceId, double voltage) {
Queue<String> queue = new LinkedList<>();
queue.add(startDeviceId);
while (!queue.isEmpty()) {
String deviceId = queue.poll();
Device device = devices.get(deviceId);
if (device == null) {
continue;
}
device.voltage = voltage;
device.updateState();
for (List<String> connection : connections) {
if (connection.contains(deviceId + "-2")) {
for (String conn : connection) {
String[] parts = conn.split("-");
String nextDeviceId = parts[0];
int pin = Integer.parseInt(parts[1]);
Device nextDevice = devices.get(nextDeviceId);
if (nextDevice != null && !nextDeviceId.equals(deviceId) && pin == 1) {
queue.add(nextDeviceId);
}
}
}
}
}
}
public void printStatus() {
Device d1 = devices.get("D1");
Device d2 = devices.get("D2");
Device d3 = devices.get("D3");
Device k1 = devices.get("K1");
Device k2 = devices.get("K2");
Device l1 = devices.get("L1");
System.out.println(k1.getStatus());
System.out.println(k2.getStatus());
System.out.println(l1.getStatus());
if(d1.getStatus().split(":")[1].equals("turned on")) {
System.out.println(d1.getStatus().split(":")[0]+":0");
}
if(d2.getStatus().split(":")[1].equals("turned on")) {
System.out.println(d2.getStatus().split(":")[0]+":0");
}
if(d3.getStatus().split(":")[1].equals("turned on")) {
System.out.println(d3.getStatus().split(":")[0]+":0");
}
}
}
在這電路類中不但需要儲存串並聯電路,還需對處理後的電路結果進行輸出。
踩坑心得
在類設計中不能合理構建各個所需的類,在類比電路的題目中我不能夠很好的理解其中的引腳與電路電壓之間的關係,從而設計了太多的無用類使得程式碼變得更為臃腫,大大降低了程式碼可讀性。在之後迭代中我也使用抽象類來對其進行了修改:
abstract class Device {
String id;
int pin1;
int pin2;
double voltage; // 電壓
double resistance; // 電阻
public Device(String id, int pin1, int pin2) {
this.id = id;
this.pin1 = pin1;
this.pin2 = pin2;
this.voltage = 0;
this.resistance = 0;
}
abstract void updateState();
abstract String getStatus();
}
這也使得裝置類的子類能夠直接使用其中的方法與屬性。
總結
透過這三次的實驗,我也對繼承和抽象有了更深層的理解,並且繼承和多型是Java物件導向程式設計中非常重要的概念。繼承可以實現類之間的層次關係,提高程式碼的複用性和可維護性;而多型可以實現同一操作在不同物件上的不同行為。掌握繼承和多型的概念和應用,可以讓程式碼更靈活、可擴充套件,並提高開發效率。透過抽象,可以隱藏物件的底層實現細節,關注物件的行為和屬性。抽象類和介面提供了一種規範化的程式設計方式,使得程式碼更加簡潔、可擴充套件,並且可以實現多型。掌握抽象的概念和應用,可以提高程式碼的可維護性和擴充套件性。