OPP前三次作業總結

開心不能傷心發表於2023-03-26

OPP前三次作業總結

前言:

前三次oop訓練集的題目量不多,前三次題量總計25題,難度也是旨在讓我們從易到難來理解,自學java的語法,所以難度適中。
第一次OPP訓練集:
第一次訓練集集中於讓我們熟悉java的語法,很多題目其實都用C語言寫過了,難度不是很大。
第二次OPP訓練集:
第二次訓練集主要集中訓練我們的邏輯思維,其中的大量題目都要運用各種判斷來解題。
第三次OOP訓練集:
-第一次訓練集主要考察類的建立和規範,其中7-3,7-4兩題難度相對其他題目要難一些,但是7-3的程式碼可以用在7-4上,可以檢驗你的程式碼是否可以重複利用,是否有可持續性。

第一次OOP訓練:

7-7 有重複的資料

設計與分析:

設計
將整數存入陣列,在將陣列從小到大排序,在用迴圈比對相鄰的兩個數,如果相同則輸出NO,如果比對到最後則輸出YES
分析
一開始我寫的是將陣列中的整數與這個數前的所有數比對,後來發現執行超時,所以這種暴力比對是不行的,後來改用排序後。只要比對相鄰兩數就可以了,大大減少時間複雜度。

具體程式碼

點選展開檢視程式碼

import java.util.Scanner;
import java.util.Arrays;
public class Main{
    public static void main(String[] args){
        Scanner in=new Scanner(System.in);
        int a=in.nextInt();
        int []b=new int[a];
        for(int i=0;i<a;i++)
        {
            b[i]=in.nextInt();
        } 
        boolean f=true;
        Arrays.sort(b);
        for(int i=0;i<a;i++)
        {
            if(i==a-1)break;
            if(b[i]==b[i+1])
                f=false;
        }
        if(f==true)
            System.out.println("NO");
        else
            System.out.println("YES");
    }
}

生成報表

踩坑心得

一開始一直執行超時,這道題需要效率更高的方法來解題。這類只需要輸出結果YES,NO的,就可以用這種排序的方法。遇到執行超時這種錯誤的話,需要及時更改解題演算法。

改進建議

這題其實可以創造一個類出來,並且把程式碼寫的更規範,這樣在後續類似的題目中,能夠重複利用程式碼,做到可持續性。

7-8 從一個字串中移除包含在另一個字串中的字元

設計與分析:

設計
將兩行輸入存入字元陣列,將第一行的字元陣列一個個與第二行的比較,如果都不相同,則追加到新的字元序列上。
分析
這種題目一看就有,我就有兩種解題思路,一種在原有的基礎上減去相同的,一種是追加不同的。而我選的第二種,那麼就要用到StringBuffer類中的append()方法,在用toSring()轉換成字串輸出。

具體程式碼

點選展開檢視程式碼

import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner in=new Scanner(System.in);
        String aa=in.nextLine();
        String bb=in.nextLine();
        char a[]=aa.toCharArray();
        char b[]=bb.toCharArray();
        boolean f=true;
        int La=aa.length();
        int Lb=bb.length();
        StringBuffer sb=new StringBuffer();
        for(int i=0;i<La;i++)
        {
            f=true;
            for(int j=0;j<Lb;j++)
            {
                if(a[i]==b[j])
                {
                    f=false;
                    break;
                }
            }
            if(f==true)
            {
                StringBuffer sb1=sb.append(a[i]);
            }
        }
        String s=sb.toString();
        System.out.println(s);
    }
}

生成報表

踩坑心得

一開始是沒有想到用StringBuffer類中的append()方法的,因為剛開始用Java寫作業,對Java中的類不熟,後來在CSDN瞭解java各種常用類與方法的時候看到後,也是毫不猶豫的用這個辦法來解題,瞭解多一點的類與方法,而且要去在實際題目中去運用它,這樣可以很高的提高做題效率,可能一開始的時候會很慢,但是也是一種積累的辦法。

改進建議

這題一樣,書寫不規範,可讀性很低,不利於後期的改進和持續性開發。這題也可以與上一題寫進一個關於陣列的去重的類中,做到持續開發完善。

第二次OOP訓練集:

7-8 判斷三角形型別

設計與分析:

設計
將輸入的三條邊先進行合法判斷,在進行各種三角型的邏輯判斷
分析
三角形型別判斷就要運用好勾股定理,並且有的三角形有著包含關係,就像等腰直角三角型包含在等腰三角型中,要合理的減少程式碼量,做到簡潔,可讀。

具體程式碼

點選展開檢視程式碼

import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner in=new Scanner(System.in);
        float a=in.nextFloat();
        float b=in.nextFloat();
        float c=in.nextFloat();
        if(a<1||a>200||b<1||b>200||c<1||c>200){
            System.out.print("Wrong Format");
            return;
        }
        if((a+b)<=c||(a+c)<=b||(b+c)<=a){
            System.out.print("Not a triangle");
            return;
        }
        else{
            if(a==b&&b==c){
                System.out.print("Equilateral triangle");
                return;
            }//(a==b||b==a||c==a)&&(Pow(a)+Pow(b)==Pow(c)||Pow(c)+Pow(b)==Pow(a)||Pow(a)+Pow(c)==Pow(b))
            else if((a==b&&Pow(a)+Pow(b)-Pow(c)<0.000001)||(b==c&&Pow(c)+Pow(b)-Pow(a)<0.000001 )||(a==c&&Pow(a)+Pow(c)-Pow(b)<0.000001)){
                System.out.print("Isosceles right-angled triangle");
                return;
            }
            else if((Pow(a)+Pow(b)==Pow(c)||Pow(c)+Pow(b)==Pow(a)||Pow(a)+Pow(c)==Pow(b))){
                System.out.print("Right-angled triangle");
                return;
            }
            else if((a==b||b==c||c==a)){
                System.out.print("Isosceles triangle");
                return;
            }
            else{
                System.out.print("General triangle");
                return;
            } 
        }
        //System.out.print(Pow(2));
        //System.out.print(a+" "+b+" "+c);
    }
    public static float Pow(float a){
        return a*a;
    }
}

生成報表

踩坑心得

有個坑卡了我很久,就是直角三角型的判斷,大家都知道直角三角型的判斷就是a2+b2=c2,所以我的程式碼也是這樣寫的,但是提交後一直報錯。一直看程式碼也沒有發現錯誤。後來才發現計算機的計算與我們人的計算不一樣,這是因為計算機中對於浮點數的計算方式而導致的問題。例如0.1+0.7=0.7999999999999999。所以我會一直卡在直角三角形這。只需要將判斷改為在誤差在0.000001之內就可以過了。另外這種邏輯類題目一定要保持好可讀性,因為我在報錯之後修改或者隔一段時間再來繼續寫的話,會減慢你寫的速度,因為你的可讀性太差或者沒有註釋的話,就要重新去看邏輯,重新跟上寫的思路。

改進建議

這題應該建立一個判斷三角形型別的類,做到重複利用。可讀性比第一次作業高一點了,但仍然可以改進。

7-9 求下一天

設計與分析:

設計
獲取資料後先判斷是否合法,然後判斷是否為閏年,再判斷是否為月末,年末。
分析
這題的要點就是月末和年末要改變月和年,並且還有閏年的二月是29天這些都是這題注意的點。題目難度不大,但注重邏輯和細節的考察。

具體程式碼

點選展開檢視程式碼

import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner in=new Scanner(System.in);
        int year=in.nextInt();
        int month=in.nextInt();
        int day=in.nextInt();
        boolean f=true;
        boolean Run=false;
        if(checkInputValidity(year,month,day)){
            nextDate(year,month,day);
        }
        else{
            System.out.print("Wrong Format");
            return;
        }
    }
    public static boolean isLamonth(int month){
        if(month==1||month==3||month==5||month==7||month==8||month==10||month==12){
            return true;
        }
        else{
            return false;
        }
    }
    public static boolean isLeapYear(int year){
        if((year%4==0&&year%100!=0)||(year%400==0)){
            return true;
        }
        else{
            return false;
        }
    }
    public static boolean checkInputValidity(int year,int month,int day){//||(day>=1&&day<=31)
        if((year>=1820&&year<=2020)&&(month>=1&&month<=12)){
                if(isLamonth(month)&&(day>=1&&day<=31)){
                    return true;
                }
                else if(month==2&&(day>=1&&day<=29)&&isLeapYear(year)){
                    return true;
                }
                else if(month==2&&(day>=1&&day<=28)&&!isLeapYear(year)){
                    return true;
                }
                else if(!isLamonth(month)&&(month!=2)&&(day>=1&&day<=30)){
                    return true;
                }
        }
            return false;
    }
    public static void nextDate(int year,int month,int day){
        if(month==2){
            if((day==29&&isLeapYear(year))||(day==28&&!isLeapYear(year)) ){
                System.out.print("Next date is:"+year+'-'+(month+1)+"-"+"1");
            }
            else if((month!=29&&isLeapYear(year))||(month!=28&&!isLeapYear(year))){
                System.out.print("Next date is:"+year+'-'+month+"-"+(day+1)) ;
            }
        }
        else{
            if((isLamonth(month)&&day==31)||(!isLamonth(month)&&day==30) ){
                if(month==12){
                    System.out.print("Next date is:"+(year+1)+'-'+"1"+"-"+"1");
                    return;
                }
                System.out.print("Next date is:"+year+'-'+(month+1)+"-"+"1");
            }
            else if((isLamonth(month)&&day!=31)||(!isLamonth(month)&&day!=30) ){
                System.out.print("Next date is:"+year+'-'+month+"-"+(day+1));
            }
        }
    }
}

生成報表

踩坑心得

這題難度較低,要注意的就是閏年的判斷和月末,年末的下一天是不一樣的。這題我在寫的時候出現的錯誤就是非法資料的判斷條件寫錯了,這是一個細節問題,改了之後直接過了,所以題目不難,認真寫很容易過的。

改進建議

這題寫的太亂了,很多可以放到一起的邏輯判斷我給分開了,程式碼冗長,而且可讀性很低,並且沒有合理的用註釋解釋,應該在必要的地方用註釋解釋,這樣在後期改進,開發的時候減少時間,提高效率。

第三次OOP訓練集:

7-3 定義日期類

設計與分析:

類圖:

分析
這題主要考察我們根據類圖來編寫類,以為第一次接觸類,所以題目不難,但是要注意的是程式碼的可讀性和可持續性,想下一題也是日期類的題目,這個類寫的規不規範,就看能不能直接放到下一題運用,在我看來,這才是一個好的程式碼設計。

具體程式碼

點選展開檢視程式碼

import java.util.Scanner;
class Date{
    private int year=0;
    private int month=0;
    private int day=0;
    public int mon_maxnum[]=new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31};
    public Date(){
    }
    public Date(int year,int month,int day){
        this.year=year;
        this.month=month;
        this.day=day;
    }
    public int getYear(){
        return this.year;
    }
    public void setYear(int year){
        this.year=year;
    }
    public int getMonth(){
        return this.month;
    }
    public void setMonth(int month){
        this.month=month;
    }
    public int getDay(){
        return this.day;
    }
    public void setDay(int day){
        this.day=day;
    }
    public boolean isLeapYear(int year){
        if((year%4==0&&year%100!=0)||year%400==0){
            return true;
        }
        else{
            return false;
        }
    }
    public boolean checkInputValidity(){
        if(this.year>=1900&&this.year<=2000){
            if(isLeapYear(year)){
                setFebruaryMaxDay(month);
            }
            if(this.month>=1&&this.month<=12){if(this.day>=1&&this.day<=mon_maxnum[this.month]){
                    return true;
                }
                else{
                    return false;
                }
            }
            else{
                return false;
            }
        }
        else{
            return false;
        }
    }
    public void getNextDate(){
        if(this.day==this.mon_maxnum[month]){
            if(this.month==12){
                this.year=this.year+1;
                this.month=1;
                this.day=1;
            }
            else{
                this.month=this.month+1;
                this.day=1;
            }
        }
        else{
            this.day=this.day+1;
        }
    }
    public void setFebruaryMaxDay(int month){
        this.mon_maxnum[2]=29;
    }
    }
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int year=in.nextInt();
        int month=in.nextInt();
        int day=in.nextInt();
        Date date =new Date(year,month,day);
        if(!date.checkInputValidity()){
            System.out.println("Date Format is Wrong");
            return;
        }
        else{
            date.getNextDate();
            System.out.print("Next day is:"+date.getYear()+"-"+date.getMonth()+"-"+date.getDay());
        }
    }
}
**生成報表** ![](https://img2023.cnblogs.com/blog/3144369/202303/3144369-20230326101258490-746503504.png)

踩坑心得

這一題難度不大,但是要注意很多細節,我提交的第一次以為年的合法範圍寫錯,一個小的細節卡了挺久的。所以我認為軟體的特殊性就是沒有過程分,只有執行和執行不了兩種結果,就算再厲害的技術也要注重細節,不然真的會浪費很多時間去處理這些“很簡單”的錯誤。另外即使能夠透過,也要把程式碼寫的易讀,易修改。方便下一次重複利用這個類,提高效率。

改進建議

這是第一次寫類,當時程式碼的書寫規範還是不錯的,就是其中checkInputValidity()方法的書寫還是太亂了,可讀性低,可以改進。

7-4 日期類設計

設計與分析:

類圖:

分析
這題可以延用上一題的程式碼進行擴寫,同樣的類進行擴寫,解決不同的問題,這題有三種情況:
第一種:輸出輸入日期的下n天
第二種:輸出輸入日期的前n天
第三種:輸出兩個日期之間相差的天數
這三種題目的解題思路都差不多,唯一需要注意的就是閏年的二月是29天,具體思路就是將n天與365天比較,再與各個月的天數比較,這樣可以減小時間複雜度。

具體程式碼

點選展開檢視程式碼

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int year = 0;
        int month = 0;
        int day = 0;
        int choice = input.nextInt();
        if (choice == 1) { // test getNextNDays method
            int m = 0;
            year = Integer.parseInt(input.next());
            month = Integer.parseInt(input.next());
            day = Integer.parseInt(input.next());
            DateUtil date = new DateUtil(year, month, day);
            if (!date.checkInputValidity()) {
                System.out.println("Wrong Format");
                System.exit(0);
            }
            m = input.nextInt();//下一天數
            if (m < 0) {
                System.out.println("Wrong Format");
                System.exit(0);
            }
            System.out.print(date.getYear() + "-" + date.getMonth() + "-" + date.getDay() + " next " + m + " days is:");
            System.out.println(date.getNextNDays(m).showDate());
        } else if (choice == 2) { // test getPreviousNDays method
            int n = 0;
            year = Integer.parseInt(input.next());
            month = Integer.parseInt(input.next());
            day = Integer.parseInt(input.next());
            DateUtil date = new DateUtil(year, month, day);
            if (!date.checkInputValidity()) {
                System.out.println("Wrong Format");
                System.exit(0);
            }
            n = input.nextInt();
            if (n < 0) {
                System.out.println("Wrong Format");
                System.exit(0);
            }
            System.out.print(
                    date.getYear() + "-" + date.getMonth() + "-" + date.getDay() + " previous " + n + " days is:");
            System.out.println(date.getPreviousNDays(n).showDate());
        } else if (choice == 3) {    //test getDaysofDates method
            year = Integer.parseInt(input.next());
            month = Integer.parseInt(input.next());
            day = Integer.parseInt(input.next());
            int anotherYear = Integer.parseInt(input.next());
            int anotherMonth = Integer.parseInt(input.next());
            int anotherDay = Integer.parseInt(input.next());
            DateUtil fromDate = new DateUtil(year, month, day);
            DateUtil toDate = new DateUtil(anotherYear, anotherMonth, anotherDay);
            if (fromDate.checkInputValidity() && toDate.checkInputValidity()) {
                System.out.println("The days between " + fromDate.showDate() + 
                        " and " + toDate.showDate() + " are:"
                        + fromDate.getDaysofDates(toDate));
            } else {
                System.out.println("Wrong Format");
                System.exit(0);
            }
        }
        else{
            System.out.println("Wrong Format");
            System.exit(0);
        }        
    }
}
class DateUtil{
    private int year=0;
    private int month=0;
    private int day=0;
    public int mon_maxnum[]=new int[]{31,31,28,31,30,31,30,31,31,30,31,30,31};
    public DateUtil(){
    }
    public DateUtil(int year,int month,int day){
        this.year=year;
        this.month=month;
        this.day=day;
    }
    public int getYear(){
        return this.year;
    }
    public void setYear(int year){
        this.year=year;
    }
    public int getMonth(){
        return this.month;
    }
    public void setMonth(int month){
        this.month=month;
    }
    public int getDay(){
        return this.day;
    }
    public void setDay(int day){
        this.day=day;
    }
    public boolean checkInputValidity(){//檢測輸入的年、月、日是否合法
        if(this.year>=1820&&this.year<=2020){
            if(isLeapYear(year)){
                setFebruaryMaxDay(this.month);
            }
            if(this.month>=1&&this.month<=12){
                if(this.day>=1&&this.day<=mon_maxnum[this.month]){
                    return true;
                }
                else{
                    return false;
                }
            }
            else{
                return false;
            }
        }
        else{
            return false;
        }
    }
    public boolean isLeapYear(int year){//判斷year是否為閏年
        if((year%4==0&&year%100!=0)||year%400==0){
            return true;
        }
        else{
            return false;
        }
    }
    public DateUtil getNextNDays(int n){//取得year-month-day的下n天日期
        while(n>(mon_maxnum[month]-day)){
            if(isLeapYear(year)){
                mon_maxnum[2]=29;
            }
            else{
                mon_maxnum[2]=28;
            }
            n=n-(mon_maxnum[month]-day);
            day=0;
            month++;
            if(month>12){
                year+=1;
                month=1;
            }
        }
        day=day+n;
        DateUtil nextNDay = new DateUtil(year,month,day);
        return nextNDay;
    }
    public DateUtil getPreviousNDays(int n){//取得year-month-day的前n天日期
        int yearP=year;
        int monthP=month;
        int dayP=day;
        while(n>=mon_maxnum[monthP]||n>=dayP){
            if(isLeapYear(yearP)){
                mon_maxnum[2]=29;
            }
            else{
                mon_maxnum[2]=28;
            }
            n=n-(mon_maxnum[monthP-1]);
            monthP--;
            if(monthP==0){
                yearP-=1;
                monthP=12;
            }
        }
        dayP=dayP-n;
        DateUtil previousNDay = new DateUtil(yearP,monthP,dayP);
        return previousNDay;
    }
    public boolean compareDates(DateUtil date){//比較當前日期與date的大小(先後)//先大為真
        if(this.year>date.year){
            return true;
        }
        else if(this.year==date.year){
            if(this.month>date.month){
                return true;
            }
            else if(this.month==date.month){
                if(this.day>=date.day){
                    return true;
                }
                return false;
            }
            return false;
        }
        return false;
    }
    public boolean equalTwoDates(DateUtil date){//判斷兩個日期是否相等
        if(this.year==date.year&&this.month==date.month&&this.day==date.day){
            return true;
        }
        return false;
    }
    public int getDaysofDates(DateUtil date){//求當前日期與date之間相差的天數
        int differDay=0;
        int biggerYear;
        int biggerMonth;
        int biggerDay;
        int smallerYear;
        int smallerMonth;
        int smallerDay;
        if(equalTwoDates(date)){
            return 0;
        }
        if(compareDates( date)){
            biggerYear=this.year;
            biggerMonth=this.month;
            biggerDay=this.day;
            smallerYear=date.year;
            smallerMonth=date.month;
            smallerDay=date.day;
        }
        else{
            biggerYear=date.year;
            biggerMonth=date.month;
            biggerDay=date.day;
            smallerYear=this.year;
            smallerMonth=this.month;
            smallerDay=this.day;
        }
            while(biggerYear>smallerYear){
                if(isLeapYear(smallerYear)){
                    differDay+=366;
                    }
                else{
                    differDay+=365;
                }
                    smallerYear+=1;
            }
            while(biggerMonth>smallerMonth){
                if(isLeapYear(smallerYear)){
                    mon_maxnum[2]=29;
                }
                else{
                    mon_maxnum[2]=28;
                }
                differDay+=mon_maxnum[smallerMonth];
                smallerMonth+=1;
            }
            while(biggerMonth

生成報表

踩坑心得:

如圖,這題我寫的時候出現的bug就是記憶體不足,我換了各種演算法依然不行,到最後開始尋找各種減小記憶體的方法是發現,一開始DateUtil類的屬性,年,月,日都是用Integer來定義,然而Integer佔28位元組堆記憶體,而int僅佔4位元組堆記憶體。知道原因後難怪會記憶體超限。後來就改了這一個地方這題就直接滿分了,所以我真的發現細節和基礎知識的積累很重要。就因為這個記憶體超限我就花了2個小時的時間去解決,幸好最後也是過了。

改進建議

這一題用到了上一題所寫的程式碼,當時不能直接使用,所以程式碼寫的沒有很嚴謹,換了個環境可能就不能用了,所以可以在其中常用的方法中將其改的更嚴謹,更易修改,遵循單一原則,每個方法只做一件事,顯然這題寫的程式碼並沒有全部遵循,但可以改進,讓程式碼呈現高內聚,低耦合。

總結:

這三次訓練集從易到難,也是為了讓我們熟悉java,所以題目難度整體偏低,在我寫題,回顧的時候,也發現了自身的幾個大問題,第一點就是不太細心,其中很多題出現的BUG都是因為疏忽大意,沒有注重細節導致的。第二點就是基礎知識不太紮實,還需要多看書,和相關的教學影片進行鞏固和溫習。第三點就是自己的演算法的理解和認識都比較少,之後要主動的去了解各類演算法,提升程式碼素養。第四點就是提高程式碼的規範性和可讀性,老師發了有關規範性的阿里巴巴開發手冊,還需要之後認真的瀏覽,並養成良好的程式碼習慣。並且之後我打算在後續的題目中,多用新的方法去解決問題了,有意識的讓程式碼具有可持續性,可以重複利用。在一定程度上,逐漸對軟體工程有了更深刻的理解,我覺得軟體工程的核心不在於寫程式碼,而是在於如何設計一個簡潔,易懂,易修改,且可持續性的設計方案,減少書寫時的BUG。這些就是我對這三次訓練集的感悟。

相關文章