第二次大作業Blog

qianmeng406發表於2024-06-06

目錄
  • 前言
  • 設計與分析
  • 踩坑心得
  • 改進建議
  • 總結

前言

  • 知識點:
  1. 類與物件的應用:
    在三次大作業中,類與物件的應用無疑是核心和基礎。這充分體現了Java作為一種物件導向程式語言的特性。透過定義類,我們可以建立具有特定屬性和行為的物件,從而構建出複雜的程式邏輯。在每次大作業中,我們都需要根據題目要求定義不同的類,如學生類、課程類、電器類等,併為這些類建立物件以進行實際操作。物件的建立、屬性的設定和方法的呼叫是我們在大作業中最常進行的基本操作,它們共同構成了程式執行的基石。

  2. 字串與陣列的應用:
    在第四次大作業中,字串與陣列的應用顯得尤為重要。字元陣列作為儲存char型別資料的基本結構,在處理輸入資訊時發揮了關鍵作用。我們可以利用字元陣列來儲存使用者的輸入,然後透過訪問、宣告和初始化等操作對資訊進行提取和處理。此外,字串之間的對比和轉換操作也是處理輸入資訊時必不可少的步驟。這些操作幫助我們篩選出需要的資訊,為後續的正規表示式匹配和資料處理提供了基礎。

  3. 正規表示式的應用:
    在處理輸入資訊時,正規表示式提供了一種高效且系統的方法。它能夠精確地匹配特定字元和擷取特定字串,使得資訊處理的過程更加便捷和準確。透過將正規表示式與字串轉換相結合,我們可以輕鬆地對輸入資訊進行格式化和提取,從而滿足大作業中的特定需求。正規表示式的應用不僅提高了程式碼的可讀性和可維護性,還大大提高了程式執行的效率。

  4. ArrayList的使用:
    在新的系列大作業中,我開始使用ArrayList來替代傳統的陣列進行資料儲存和呼叫。這一改變帶來了諸多好處。首先,ArrayList具有動態調整大小的能力,可以根據需要自動擴充套件或縮小容量,從而避免了陣列越界的問題。其次,ArrayList提供了豐富的API供我們呼叫,使得資料的新增、刪除和查詢等操作變得更加便捷和高效。最後,ArrayList的使用使得程式碼更加靈活和可擴充套件,能夠適應更多的場景和需求。

  5. 抽象與繼承的應用:
    在對資料類進行定義時,抽象與繼承的應用使得程式碼結構更加清晰和易於維護。透過定義抽象類,我們可以提取出不同子類之間的共同屬性和方法,從而減少了程式碼的冗餘和重複。同時,繼承機制使得子類能夠繼承父類的屬性和方法,並在此基礎上進行擴充套件和重寫。這使得我們在對各個物件進行統一操作時,只需要使用父類物件即可,提高了程式碼的複用性和可維護性。此外,抽象與繼承的應用還有助於我們更好地組織和管理程式碼,使得程式結構更加合理和易於理解。

  • 題量:這三次大作業的題量相比上三次要變大了一些,程式碼的行數也逐漸增加到了千行,但對我來說不存在做不完的情況。

  • 難度:除開第四次大作業沒有涉計完整拿了79分以外,第五次和第六次都及時地完成拿到了滿分,所已難度方面我覺得還可以,主要還是因為自己的java水平在不斷提升,近兩次大作業做起來都得心應手。

設計與分析

  • 第四次大作業:

第四次大作業在第三次的基礎上進行了顯著的改進和最佳化,不僅在資料儲存機制和類關係設計上有所提升,而且在資訊處理和匹配上也採用了更加高效的正規表示式方法。這些改動使得程式碼結構更加規整,提高了程式碼的可讀性和可維護性。

在這次作業中,透過使用繼承關係,程式碼成功地對單選、多選和填空題的資訊儲存和處理進行了統一處理,從而減少了程式碼的冗餘和重複。這種設計思路不僅提高了程式碼的效率,也使得程式碼更加靈活,能夠適應更多型別的題目。

然而,這次作業也存在一些不足之處。其中,最顯著的問題是沒有對多試卷進行判定處理。這導致在多試卷測試點上全敗,只拿了單試卷的分。這個問題可能是由於對需求理解不夠深入或者時間緊迫等原因導致的,需要在後續的改進中加以解決,但是解決起來好像會需要重寫底層邏輯,心累。。。

另外,這次作業依然沒有使用ArrayList進行資訊的儲存,而是採用了大量的陣列定義。雖然陣列在某些情況下能夠滿足需求,但相比之下,ArrayList具有更加靈活和強大的功能,能夠動態地調整大小,使得程式碼更加簡潔和易於管理。如果像第五次和第六次大作業一樣使用ArrayList進行資訊儲存,相信會進一步提升程式碼的質量和效率。

綜上所述,第四次大作業在第三次的基礎上取得了顯著的進步,但在多試卷處理和資料儲存機制上還有待改進。透過進一步深入理解和分析需求,採用更加靈活和高效的資料結構和方法,相信可以在未來的作業中取得更好的成績。

  • 第五次大作業

第五次大作業進入全新系列-家電電路控制模擬,乍一看很複雜,實則做起來還不及第四次大作業,可能是因為是第一次迭代。

第五次大作業終於開始用ArrayList儲存資料和處理資料了,這樣對程式碼的的資料管理就更加靈活和系統,真棒。對資訊的處理全部都是用正規表示式進行匹配和錄入,對於正規表示式的應用已經得心應手了。

該次大作業定義了一個父類Machine,思路上將所有電器和控制開關都設為子類,這樣可以方便進行資料處理。主線所有的電器連通狀態都用了一個特徵值tlj來判定,對線路是否通暢進行判斷和處理。主線路直接定義一條引數化為Machine的連結串列進行儲存各個電器和控制裝置,方便逐一處理他們的電壓和工作狀態。

最後在排序輸出時是單純的按電器種類迴圈匹配輸出,沒有做電器編號大小排序,不過這一點在第六次大作業中得到了解決。

  • 第六次大作業

第六次大作業真的開始複雜起來了,用了我總計14個小時的時間對第五次的程式碼進行改進,然後用了4個小時對資料進行排查和改正,最終在室友的提醒下改進資料精度之後拿下滿分。第六次大作業光看類圖就能看出其難度,這也是我大作業第一次上千行程式碼,不過好多程式碼的運算邏輯都是重複的,估計學會用介面之後會方便一點吧。第六次大作業相比第五次大作業新增思路有:
1.將並聯電路看成Machine的子類,再定義一個獨有屬性ArrayList來儲存並聯電路中電器的資訊。

2.計算總電流和並聯電路電流來計算各個電器電壓,這個計算建立在第六次大作業增加了電阻機制,計算完總電流和並聯電路總電阻後可以開始對並聯電路電壓開始計算。

3.並聯電路的通路判定也增加btlj特徵值,這樣便於判斷分路的通路和主路的通路的狀態。

4.對於電器輸出做了提前排序,現在的排序程式碼示例:
for(int i=0;i<tid;i++)
{
for(int j=0;j<tid-1;j++)
{
char[] fid1=ids[j].toCharArray();
char[] fid2=ids[j+1].toCharArray();
int t1=Character.getNumericValue(fid1[1]);
int t2=Character.getNumericValue(fid2[1]);
String ft;
if(t1>t2)
{
ft=ids[j+1];
ids[j+1]=ids[j];
ids[j]=ft;
}
}
}
邏輯把所有電器都存到一個ids陣列裡,用冒泡排完序之後同種電器的字尾編號肯定就分前後了,然後用匹配輸出程式碼把每種電器都匹配迴圈輸出一遍。不過在輸出時還是和第五次大作業一樣每一種電器種類都迴圈了一遍。

踩坑心得

  • 第四次大作業
    第四次大作業感覺除了沒做多試卷處理之外對單試卷的處理已經差不多了,沒有什麼問題,就是陣列存資料容易產生越界報錯和警告,有以下小問題:
    1.在對多選題進行答題判定時初代邏輯僅僅是隻要出現了部分正確答案就判斷為部分正確,導致答案多選時也判定為部分正確。
    解決方法:只要修改一下判定邏輯就好了。
    2.和前三次大作業一樣沒有做空格判定,導致好多次都是格式錯誤。。。

  • 第五次大作業
    第五次大作業由於第一次使用ArrayList有點不熟練,產生了很多警告和錯誤,比如
    ArrayList machines;

然後直接machines.add(a)或machines.set(1,a),出現machines is null 的錯誤,一直以為是越界問題,結果是沒有new定義,僅僅抽象定義是不夠的,然後改成了:
ArrayList machines=new ArrayList<>();

還有就是定義了一個light的子類繼承Machine,然後定義blight(白熾燈)和rlight(日光燈)來繼承light,結果導致出現:
Machine machine=machines.get(i);
machines.display();
時不能正確按對應類的display輸出,問題出在二次繼承時light沒有寫入display()來繼承Machine的屬性.
改正措施:將light父類直接刪掉,rlight和blight直接繼承Machine。

在對分檔調節器進行處理時,初代程式碼的邏輯是換擋就算一次電壓,結果導致電壓計算錯誤,我還查了好久的資料。
改正措施:在判斷到分檔調節器的狀態改變資訊時,先改變完分檔調節器的檔位,在狀態資訊處理完之後再對分檔調節器的電壓進行計算。

  • 第六次大作業
    第六次大作業因為是在第五次大作業上改進,沒有出現什麼大錯誤,但還是有小問題,由於該次迭代沒有給測試點特徵,所以好多種情況一開始真沒想到,有下:
    1.電源VCC後直接接並聯電路

    #T1:[IN K1-1] [K1-2 D2-1] [D2-2 OUT]
    #T2:[IN K2-1] [K2-2 D1-1] [D1-2 OUT]
    #M1:[T1 T2]
    #T3:[VCC M1-IN] [M1-OUT D3-1] [D3-2 GND]
    #K1
    #K2
    end
    這種情況對於我的初代程式碼會有匹配錯誤,因為我的正規表示式只做了VCC之後接控制器和電器的判斷,沒有做接並聯。

2.並聯電路之後接開關。

#T1:[IN K1-1] [K1-2 D2-1] [D2-2 OUT]
#T2:[IN K2-1] [K2-2 D1-1] [D1-2 OUT]
#M1:[T1 T2]
#T3:[VCC L1-1] [L1-2 M1-IN] [M1-OUT K3-1] [K3-2 GND]
#K1
#K2
#L1:1.00
end
這種情況會越過我初代程式碼的通路判定。

3.多並聯電路

#T1:[IN K1-1] [K1-2 D2-1] [D2-2 OUT]
#T2:[IN K2-1] [K2-2 D1-1] [D1-2 OUT]
#T3:[IN D1-1] [D1-2 OUT]
#M1:[T1 T2]
#T3:[VCC L1-1] [L1-2 M1-IN] [M1-OUT K3-1] [K3-2 GND]
#K1
#K2
#L1:1.00
end
對於這一點,初代程式碼是僅僅對二並聯進行了處理,結果僅僅拿了個48分,我還納悶為啥只有這點分,結果細想之後悟了,又花了大把時間開始進行多並聯判定的程式碼改正。

還有就是在計算並聯電路總電阻時,使用倒數之和相加會出現測試點18和21出錯,這是資料精度問題,在和其他一樣出錯的人商討之後改用兩兩相乘除以相加的運算邏輯進行計算,然後就過了。

改進建議

1.我的每一次大作業程式碼都會出現重複邏輯的迴圈或者是判斷,導致程式碼行數大增,改起來看得我眼睛痛,最近正在學習介面的使用,希望情況能有所好轉。
好像可以把輸出時做一個介面,我現在的輸出程式碼是(示例):
for(int i=0;i<tid;i++)
{
Pattern pattern=Pattern.compile(電器匹配字串);
Matcher matcher=pattern.matcher(匹配電器);
if(matcher.find())
{
for(int j=0;j<n;j++)
{
Machine machine=pl.get(j);
pattern=Pattern.compile(M);
matcher=pattern.matcher(machine.id);
if(matcher.find())
{
for(int k=0;k<machine.bl.length;k++)
{
if(machine.bl[k]!=null)
{
for(int q=0;q<machine.bl[k].size();q++)
{
if(machine.bl[k].get(q).id.equals(ids[i]))
{
電器類 mc=new 電器類(ids[i],machine.bl[k].get(q).cl1);
mc.setspeed();
mc.display();
break;
}
}
}
}
}
if(machine.id.equals(匹配電器))
{
電器類 mc=new 電器類(machine.id,machine.cl1);
mc.setspeed();
mc.display();
}
}
}
}
以上程式碼要對每一種電器都改一下物件迴圈一次,好像加起來有300行差不多。。。。
還有對ids[]進行排序時好像可以在Machine類裡定義一個Comparator介面,把ids[]改成ArrayList ids=new ArrayList<>(),這樣主函式里排序時只要Colletions.sort(ids)就好了,看上去更系統一點。

2.第四次大作業沒有做多試卷的判定,這一點我一直耿耿於懷,最近補練集出了,我得好好改一下。

總結

第四次大作業拿了79分,第五次和第六次都是滿分,這說明我的java水平在不斷精進,真不錯。在完成第五次和第六次大作業時學會了繼承和連結串列的使用,不過程式碼還是出現了像前四次一樣的贅餘,室友程式碼只有1000多行,我有1300多行。。。。
程式碼還是缺乏系統性,因為我還是習慣於程序導向,因為不會介面,不會排序類的使用,啥都不會。但是相比上一次總結時還是大有長進,不會出現被大作業難倒的情況。

對實驗的建議:
要是能延長一下實驗的提交時間就好了。