OO第一次部落格(前三次作業總結)

黄裕涛發表於2024-04-21

一.前言
1.第一次作業
第一次作業所需的類要求比較少,因此我直接在主方法中利用正規表示式對輸入文字進行操作。同時由於資料型別較少,我透過字串陣列便能處理資料並透過大部分測試點,但由於缺乏較好的類關聯,因此很多特殊的測試點過不去,同時由於測試點的隱藏,只透過題目給的幾個例子較難查出問題和做出改進,因此我便不了了之。第一次作業總體難度適中,主要考察正規表示式的使用,對於尚不熟練的我難度剛好,能做,但不能滿分,因為沒有寫出一個能表達所有資料情況的表示式。第一次作業題量稍多,畢竟有最後那個正規表示式的題目押軸。不過第一次作業涉及的知識點較少,主要都是基本功和正規表示式的訓練。
2.第二次作業
第二次作業由於新增答題資訊,因此需要對輸入的資訊進行甄別,因此我加入了(conten.startsWith("#N"))來區分不同型別的資料,同時使用ArrayList來對所定義的類進行組合,這既有利於對新資料的新增,也更好的增強的不同類之間的關聯,同時對於不同型別的資料存在於同一行使用(matcher.group())來進行切分,較高效的分離了所需資訊。但由於題目的逆序輸入導致對答卷資訊的判斷增加難度,同時類的使用依然不夠細分,致使無法對題目答題做出較好的正誤判斷,因此只堪堪拿到低分。第二次作業題量較少,主要為了讓我們有更多時間做最後的正規表示式的題目,其他題目依然是對基本功的訓練,大頭在於前者。不過第二次難度較大,不僅多了不同的資訊型別需要區分,而且資訊之間的關聯性更加緊密,只有設計出好的類才能更好的應對。因此這既是對正規表示式的進一步熟練度訓練,也是對類和方法的構造的一個考驗。好的類和方法可以同時應對多個較為***鑽的測試點,同時避免因為考慮不周而反覆修改程式碼。總之難度相較上次有較大提高,更加考驗水平。
3.第三次作業
第三次作業經過前兩次的迭代,難度來到了最高點,在原先的基礎上有2類資訊增加到了5類,同時增加了題目刪除要求,更加符合實際環境需求。這次有了老師對不同型別資訊的關聯和功能分析,我已有較好的思路和不錯的類的構造來應對,我針對不同的型別資訊進行相應的類的定義,並對大部分類都進行了ArrayList封裝,同時將兩種資訊存於同一類(例如將題目類和試卷題目分值封裝於Paper類中),對輸入的文字進行篩選再提取,能夠較好的提取出所有的資訊。同時對於卷面的評分判斷我選擇從試卷資訊類入手對題目題號進行篩選,再進一步對答卷資訊篩選和比較。
二.設計與分析
1.第一次作業我採用字元陣列來儲存輸入資訊,並建立新的字串陣列用於儲存分離出的所需資訊,鑑於第一次的資料型別和量較少,因此可以勉強完成所需要求。不過正規表示式的表示式不夠完美,沒法提取部分特殊的資訊,同時類太少,致使無法很好的關聯資訊。再者我將所有的答案判斷等程式碼寫在主方法中,致使程式碼臃腫,可讀性差,同時改正起來也極為不易

點選檢視程式碼

	    public static void main(String args[]){
	        Scanner input=new Scanner(System.in);
	        String ns=input.nextLine();
	        int n=Integer.parseInt(ns);
	        Qa [] a=new Qa[n];
	        String Q=new String();
	        String A=new String();
	        for(int i=0;i<n;i++){
	            Q=input.nextLine();
	            a[i]=new Qa(Q);
	        }
	        A=input.nextLine();
	        //String ent2=input.nextLine();
	        String end=input.next();
	        String content,regStr1="#N:(\\d+) *#Q:(\\S+) *#A:(\\d+)";
	        String regStr2="#A:(\\d+)";
	        Pattern pattern=Pattern.compile(regStr1);
	        Pattern pattern2=Pattern.compile(regStr2);
	        for(int i=0;i<n;i++){
	            content=a[i].getQ();
	            Matcher matcher=pattern.matcher(content);
	            while(matcher.find()){
	            a[i].num=Integer.parseInt(matcher.group(1));
	            a[i].setQq(matcher.group(2));
	            a[i].setQa(matcher.group(3));
	            }
	        }
	        String [] b=new String[n];//回答資料
	        int j=0,k=0;
	        for(int i=0;i<n;i++){
	            j=0;
	            content=A;
	            Matcher matcher2=pattern2.matcher(content);
	            while(matcher2.find()){
	                b[j]=new String();
	                b[j]=matcher2.group(1);
	                j++;
	            }
	        }
	        for(int i=0;i<n;i++){
	            for(k=0;k<n;k++){//題號
	                if((i+1)==a[k].num){
	                    break;
	                }
	            }
	            if(k==n)
	                k=n-1;
	            if(b[i].equals(a[k].getQa()))//判斷答案是否符合
	                a[k].setpan(true);
	            else a[k].setpan(false);
	        }
	        for(int i=0;i<n;i++){        //輸出
	            for(k=0;k<n;k++){//題號
	                if((i+1)==a[k].num){
	                    break;
	                }
	            }
	            if(k==n)
	                k=n-1;
	            System.out.println(a[k].getQq()+"~"+b[i]);
	        }
	        for(int i=0;i<n;i++){
	            if(i!=n-1)
	                System.out.printf(a[i].getpan()+" ");
	            else System.out.println(a[i].getpan());
	        }
	    }
	}
	class Qa{
	    private String Q=new String();//問題行
	    private String Qq=new String();//問題
	    private String Qa;//答案
	    private String A;//回答行
	    private boolean pan;//判斷
	    public int num;
	    public Qa(String Q){
	        this.Q=Q;
	    }
	    public void setA(String A){
	        this.A=A;
	    }
	    public void setQa(String Qa){
	        this.Qa=Qa;
	    }
	    public String getQa(){
	        return Qa;
	    }
	    public void setQq(String Qq){
	        this.Qq=Qq;
	    }
	    public String getQq(){
	        return Qq;
	    }
	    public void setpan(boolean pan){
	        this.pan=pan;
	    }
	    public boolean getpan(){
	        return pan;
	    }
	    public String getQ(){
	        return Q;
	    }
	    public String getA(){
	        return A;
	    }
	}
2.第二次程式碼由於增加了資訊型別的識別,既豐富了類,因此我採用了ArrayList來儲存資訊。 不過依然沒有擺脫上次的通病,在主方法中寫了主要判斷過程,致使總體結構臃腫。

點選檢視程式碼
public static void main(String args[]){
        Scanner input=new Scanner(System.in);
        String content,regStr1="#N:(\\d+) *#Q:(\\S+) *#A:(\\S+)";
        String regStr2="#S:(\\d+) +#A:(\\S+) +#A:(\\S+)";
        String regStr3="#T:(\\d+) (.+)";
        ArrayList<Paper> q=new ArrayList();//試卷
        //ArrayList<Answer> a=new ArrayList();//答卷
        ArrayList<Judg> j=new ArrayList();//評卷
        Answer a=new Answer();
        Pattern pattern1=Pattern.compile(regStr1);
        Pattern pattern2=Pattern.compile(regStr2);
        Pattern pattern3=Pattern.compile(regStr3);
        String s=input.nextLine();
        while(s.equals("end")==false){
            content=s;
            if(content.startsWith("#N")){
                Matcher matcher1=pattern1.matcher(content);
                while(matcher1.find()){
                    q.add(new Paper(matcher1.group(2),matcher1.group(3),Integer.parseInt(matcher1.group(1))));
                }
            }
            else if(content.startsWith("#S")){
                Matcher matcher2=pattern2.matcher(content);
                while(matcher2.find()){
                    for(int i=0;i<2;i++){
                        a.A[i]=new String();
                        a.A[i]=(matcher2.group(i+2));
                    }
                    a.num=(Integer.parseInt(matcher2.group(1)));
                    //a.add(new Answer(matcher1.group(2),matcher1.group(3),Integer.parseInt(matcher1.group(1))));
                }
            }
            else if(content.startsWith("#T")){
                Matcher matcher3=pattern3.matcher(content);
                while(matcher3.find()){
                    a.add(new Judg(matcher3.group(2),Integer.parseInt(matcher3.group(1))));
                    String []jf=content.split("-");
                }
            }
        }
        int sum=0;
        for(int j=0;j<2;j++){
            for(int i=0;i<2;i++){
                if(q.get(i).qnum==(j+1))//題號與答案順序相同
                    if(q.get(i).Qa.equals(a.A[j])){
                        q.get(i).o=true;
                        sum+=0;
                    }
            }
            
        }
    }
}
class Paper{//試卷
    public Paper(String group, String group2, int int1) {
		// TODO 自動生成的建構函式存根
	}
	String Q;
    String Qa;
    int qnum;//題號
    boolean o=false;
}
class Answer{//答卷
    String [] A=new String[2];
    int num;//卷號
}
class Judg{//評卷
    public Judg(String group, int int1) {
		// TODO 自動生成的建構函式存根
	}
	String p;
    int num;//卷號
}
3.第三次可以說是我的得意之作了,既對輸入資訊在主方法進行甄選後執行至相應的類中進行新增,也將不同的輸出放置於不同的方法中依次輸出相應答案。同時我使用多種類和ArrayList用以同時儲存多種資料資訊。 ![](https://img2024.cnblogs.com/blog/3432993/202404/3432993-20240421234502760-1378978677.png)
點選檢視程式碼
import java.util.*;
import java.util.ArrayList;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class Main{
    public static void main(String args[]){
        Scanner input=new Scanner(System.in);
        String s=input.nextLine();
        Paper paper=new Paper();//試卷
        Delete delete=new Delete();//刪題
        Anspaper anspaper=new Anspaper();//答卷
        Student stu=new Student();//考生
        while(s.equals("end")!=true){
            if(s.startsWith("#N"))
            {
                paper.addQA(s);
            }
            else if(s.startsWith("#T"))
            {
                paper.addFenzhi(s);
            }
            else if(s.startsWith("#S")){
                anspaper.addSqa(s);
            }
            else if(s.startsWith("#X")){
                stu.addStu(s);
            }
            else if(s.startsWith("#D")){
                delete.addDelete(s,paper);
            }
            s=input.nextLine();
        }
        ismanfen(paper);
        pinfen(anspaper,paper);
        for(int i=0;i<stu.stu.size();i++){
            if(stu.stu.get(i).id.equals(anspaper.id)){
                stu.stu.get(i).sscore=anspaper.sscore;
                System.out.printf("%s %s:",stu.stu.get(i).id,stu.stu.get(i).name);//姓名學號
                break;
            }
        }
        for(int i=0;i<paper.fen.size();i++){
            System.out.printf(" %d",anspaper.sqa.get(i).score);
        }
        System.out.printf("~%d",anspaper.sscore);
    }
    public static void ismanfen(Paper paper){
        int sum=0;
        for(int i=0;i<paper.fen.size();i++){
            sum=paper.fen.get(i).score;
        }
        if(sum<100)//無這能對22、23,有能對14
            System.out.println("alert: full score of test paper"+paper.num+" is not 100 points");
    }
    public static void pinfen(Anspaper anspaper,Paper paper){
        int k=0;
        int t=0;
        if(anspaper.num!=paper.num){
            System.out.println("The test paper number does not exist");
        }
        else{
            for(int i=0;i<paper.fen.size();i++){//#T的題號
                t=0;
                for(int j=0;j<paper.qa.size();j++)//#N的題號
                {
                    t++;
                    if(paper.fen.get(i).tnum==paper.qa.get(j).tnum){//找到題目
                        t--;
                        if(paper.qa.get(j).exit==true){//題目存在
                            for(k=0;k<anspaper.sqa.size();k++){
                                if((i+1)==anspaper.sqa.get(k).tnum){//順序題號
                                    if(anspaper.sqa.get(k).A.equals(paper.qa.get(j).A)){//答案正確
                                        anspaper.sscore+=paper.fen.get(i).score;
                                        anspaper.sqa.get(k).score=paper.fen.get(i).score;
                                        anspaper.sqa.get(k).isright=true;
                                        System.out.println(paper.qa.get(j).Q+"~"+anspaper.sqa.get(j).A+"~"+anspaper.sqa.get(k).isright);
                                    }
                                    else {
                                        anspaper.sscore+=0;
                                        anspaper.sqa.get(k).score=0;
                                        System.out.println(paper.qa.get(j).Q+"~"+anspaper.sqa.get(j).A+"~"+anspaper.sqa.get(k).isright);
                                    }
                                    break;
                                }
                            }
                            if(k==anspaper.sqa.size()){//沒有在考卷上找到題目
                                System.out.println("answer is null");
                            }
                        }
                        else System.out.println("the question "+paper.fen.get(i).tnum+" invalid~0");
                        break;
                    }
                }
                if(t==paper.qa.size())//未有該題
                    System.out.println("non-existent question~0");
            }
        }
    }
}
class Paper{//試卷
    int num;//試卷號
    ArrayList<QA> qa=new ArrayList<>();//題目
    ArrayList<Fenzhi> fen=new ArrayList<>();//分值
    public void addQA(String s){//#N題目資訊
        String regs="#N:(\\d+) #Q:(.+) #A:(.+)";
        Pattern pattern=Pattern.compile(regs);
        Matcher matcher=pattern.matcher(s);
        QA a=new QA();
        while(matcher.find()){
            a.tnum=Integer.parseInt(matcher.group(1));
            a.Q=matcher.group(2);
            a.A=matcher.group(3);
        }
        qa.add(a);
    }
    public void addFenzhi(String s){//#T試卷資訊
        String regs1="#T:(\\d+)";
        Pattern pattern1=Pattern.compile(regs1);
        Matcher matcher1=pattern1.matcher(s);
        while(matcher1.find()){
            num=Integer.parseInt(matcher1.group(1));
        }
        String regs="(\\d+)-(\\d+)";
        Pattern pattern=Pattern.compile(regs);
        Matcher matcher=pattern.matcher(s);
        Fenzhi a=new Fenzhi();
        while(matcher.find()){
            a.tnum=Integer.parseInt(matcher.group(1));
            a.score=Integer.parseInt(matcher.group(2));
            fen.add(a);
            a=new Fenzhi();
        }
    }
}
class Anspaper{//答卷#S
    int num;//試卷號
    String id;//學號
    int sscore;
    ArrayList<Sqa> sqa=new ArrayList<>();
    public void addSqa(String s){//答卷資訊#S
        String regs1="#S:(\\d+) (\\d{8})";
        Pattern pattern1=Pattern.compile(regs1);
        Matcher matcher1=pattern1.matcher(s);
        while(matcher1.find()){
            num=Integer.parseInt(matcher1.group(1));
            id=matcher1.group(2);
        }
        String regs="#A:(\\d+)-(\\S+)";
        Pattern pattern=Pattern.compile(regs);
        Matcher matcher=pattern.matcher(s);
        Sqa a=new Sqa();
        while(matcher.find()){
            a.tnum=Integer.parseInt(matcher.group(1));
            a.A=matcher.group(2);
            sqa.add(a);
            a=new Sqa();
        }
    }
}
class Student{//學生#X
    ArrayList<Stu> stu=new ArrayList<>();
    public void addStu(String s){//學生資訊#X
        String regs="(\\d{8}) (\\w+)";
        Pattern pattern=Pattern.compile(regs);
        Matcher matcher=pattern.matcher(s);
        Stu a=new Stu();
        while(matcher.find()){
            a.id=matcher.group(1);
            a.name=matcher.group(2);
            stu.add(a);
            a=new Stu();
        }
    }
}
class Delete{
    ArrayList<Integer> num=new ArrayList<>();//題號
    public void addDelete(String s,Paper paper){//刪除題目資訊#D
        Integer n=0;
        String regs="N-(\\d+)";
        Pattern pattern=Pattern.compile(regs);
        Matcher matcher=pattern.matcher(s);
        while(matcher.find()){
            n=Integer.parseInt(matcher.group(1));
        }
        if(n!=0){
            num.add(n);
            for(int i=0;i<paper.qa.size();i++){
                if(paper.qa.get(i).tnum==n){
                    paper.qa.get(i).exit=false;
                    break;
                }
            }
        }
    }
}
class Stu{//考生
    String id;
    String name;
    int sscore;
}
class Fenzhi{
    int tnum;//題號
    int score;//分值
}
class QA{//試卷題目
    int tnum;
    String Q;
    String A;
    boolean exit=true;
}
class Sqa{//學生作答
    int tnum;//順序題號
    String A;//學生答案
    int score;//題目得分
    boolean isright=false;
}

三.踩坑心得
1.第一次作業看到例題都是簡單的加減運算,便草率的使用整型陣列來儲存回答的答案,隨後便發現題目並未限制題目和答案的資料型別,於是便大刀闊斧的進行程式碼修正,同時導致很多原先寫好的類和方法不得不刪去重寫,致使花費大量時間來改正程式碼,同時由於時而使用nextLine,時而使用nextInt導致行末的換行符並未消除,導致後續輸入讀取異常,害得我除錯好一陣才找到問題所在,因此做題前一定要認真審題,特別是題目複雜時更要如此,最好能夠規劃一下要處理的資訊之間思維導圖,可以更好的的便於我們進行類的定義和方法的書寫。同時由於初學而盲目的將類中的資料用private進行隱藏導致增加書寫的複雜度。
2.第二次作業雖然使用了ArrayList增強不同型別之間的關聯性,同時還利用(conten.startsWith("#N"))更好的區分資訊型別,但是大部分操作依然還是在主方法中完成,因此程式碼可讀性差,我自己都不願意再看一遍,因此這極不利於後續程式碼的維護和修改,總之有區域性的分配功能和至關重要,既有利於後續類的構建,也有益於程式碼的美觀和可讀。
3.第三次作業雖然能應對絕大數例題,但是仍不夠完善,錯題,白卷,漏題等特殊情況扔難以應對,個人感覺是類中的資料不夠豐富,因此應新增更多變數以應對更多情況。否則就得在判斷的時候多加限制條件來判斷。(例如以下試卷題號和題目題號不對應的特殊情況)

四.改進建議
1.(1)第一次作業應將所有資料進行public或者不加以限制,以便於後續的修改和呼叫;
(2)儲存分離提取後的資料應用ArrayList封裝而非字串陣列,一方面前者可以動態改變長度,另一方面前者每個元素可以儲存多種型別的資料;
(3)資料的分離和提取應放在相應類中的進行,既增加帶碼的可讀性,有增加了可維護性,有利於後續的修復;
2.(1)第二次作業應豐富類的方法,把與相應類有關的方法放入其中,簡化複雜度;
(2)應增強類之間的關聯性,實現資料相互呼叫,有利於資訊的判斷;
3.(1)第三次作業應往類中新增更多變數以應對一些***鑽的測試點。
五.總結
這次迭代作業讓我意識到前幾次作業不可簡單的為應對例題和測試點而設計,而是要宏觀考慮不同型別資訊的關聯,以制定相應的類和方法來更好的實現,否則就會如我這次般每次作業都得拋棄上次的思路重新書寫資訊程式碼類和方法,因此統籌和宏觀的思維以及對程式碼今後維護和改正的心理準備至關重要。

相關文章