OOP前三次作业总结BLOG

发布时间 2023-03-26 16:07:56作者: B饭老司机

 

OOP 1-3次作业总结

22201303-范宇

前言

  第一次BLOG,对第一阶段的学习总结。

  前三次题目集总体上更偏向于JAVA语法上的训练,第二次与第三次题目集中的后两道需要一点逻辑思维。题量我个人认为适中,整体难度我认为恰到好处,就是那种需要一定时间思考,但又不至于难到完成不了。

设计与分析

  • 题目集一:7-7 有重复的数据,读入数据,检查是否有重复的数据。如果有,输出“YES”这三个字母;如果没有,则输出“NO”。你的程序首先会读到一个正整数n,n[1,100000],然后是n个整数。

    如果这些整数中存在重复的,就输出:

    YES
     

    否则,就输出:

    NO
    import java.util.Scanner;
    import java.util.Arrays;
    
    public class Main{
        public static void main(String[] args){
            Scanner input = new Scanner(System.in);
    	    int n=input.nextInt();
            int [] num=new int[n];
                for(int i=0;i<n;i++){
                    num[i]=input.nextInt();
                }
            Arrays.sort(num);
            int i;
            for(i=0;i<n-1;i++){
                if(num[i]==num[i+1]){
                     System.out.println("YES");
                     break;
                }
            }
            i++;
            if(i==n)
                System.out.println("NO");
    //         int i;
    //         loop:
    //         for(i=0;i<n;i++){
    //             for(int j=n-1;j>i;j--){
    //                 if(num[i]==num[j]){
    //                     System.out.println("YES");
    //                     break loop;
    //                 }
    //             }
    //         }
    //             if(i==n)
    //                 System.out.println("NO");
    
            
        }
    }

     

    这道题的整体思路就是先排序,再遍历数组,判断前一个元素与后一个元素是否相等,如果是,则重复,如果全部遍历完(也就是i==n时),则说明没有重复。这道题的重点在于当n为最大值时,这一测试点非常容易超时,之前用了双重for循环和ArrayList两种方法,都没有通过最大n这个测试点,在多次尝试下,最后发现了这个先排序的方法;后面还遇到了相似的题目,使用Set也是可行的;
  • 题目集二:7-8 判断三角形类型,输入三角形三条边,判断该三角形为什么类型的三角形。

(1)如果输入数据非法,则输出“Wrong Format”;
(2)如果输入数据合法,但三条边不能构成三角形,则输出“Not a triangle”;
(3)如果输入数据合法且能够成等边三角形,则输出“Equilateral triangle”;
(3)如果输入数据合法且能够成等腰直角三角形,则输出“Isosceles right-angled triangle”;
(5)如果输入数据合法且能够成等腰三角形,则输出“Isosceles triangle”;
(6)如果输入数据合法且能够成直角三角形,则输出“Right-angled triangle”;
(7)如果输入数据合法且能够成一般三角形,则输出“General triangle”。

import java.util.Scanner;

public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        double a=input.nextDouble();
        double b=input.nextDouble();
        double c=input.nextDouble();
        if(a<1||a>200||b<1||b>200||c<1||c>200)
            System.out.print("Wrong Format");
        else{
            double t;
            if(a<b){
                t=a;
                a=b;
                b=t;
            }
            if(a<c){
                t=a;
                a=c;
                c=t;
            }
            if(b<c){
                t=b;
                b=c;
                c=t;
            }
            if((b+c)<=a)
                System.out.print("Not a triangle");
            else if(a==b&&b==c)
                System.out.print("Equilateral triangle");
            else if(b==c&&(2*b*b-a*a)*(2*b*b-a*a)<0.00001*0.00001)
                System.out.print("Isosceles right-angled triangle");
            else if((b==c)||(b==a))
                System.out.print("Isosceles triangle");
            else if(b*b+c*c==a*a)
                System.out.print("Right-angled triangle");
            else
                System.out.print("General triangle");
        }
    }
}

这道题我先将三边按大小排序,再利用三角形构成的条件(即,两边之和大于第三边)来判断三角形是否可以构成,最后通过三边关系判断三角形的种类,其中用到了勾股定理(这里就可能涉及到无理数,而无理数在计算机中的运算是存在误差的,所以这种情况下判断条件需要把误差范围考虑进去)。

 

  • 题目集二:7-9 求下一天,输入年月日的值(均为整型数),输出该日期的下一天。
  1. 当输入数据非法及输入日期不存在时,输出“Wrong Format”;
  2. 当输入日期合法,输出下一天,格式如下:Next date is:年-月-日
import java.util.Scanner;

public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        int year=input.nextInt();
        int month=input.nextInt();
        int day=input.nextInt();
        Main in=new Main();
        if(year<1820||year>2020||month<1||month>12||day<1||day>31)
            System.out.print("Wrong Format");
        else{
            if(checkInputValidity(year,month,day)){
                in.nextDate(year,month,day);
            }
            else
                System.out.print("Wrong Format");
        }
    }
    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){
        if(isLeapYear(year)){
            if(month==2&&day>29)
                return false;
        }
        else{
            if(month==2&&day>28)
                return false;
        }
        if(month==4||month==6||month==9||month==11){
                if(day>30)
                    return false;
            }
        return true;
    }
    public static void nextDate(int year,int month,int day){
        day++;
                if(month==4||month==6||month==9||month==11){
                    if(day>30){
                        month++;
                        day=1;
                        
                    }
                }
                if(month==1||month==3||month==5||month==7||month==8||month==10||month==12){
                    if(day>31){
                        month++;
                        day=1;
                        if(month>12){
                            year++;
                            month=1;
                        }
                    }
                }
                if(month==2){
                    if(isLeapYear(year)){
                        if(day>29){
                            month++;
                            day=1;
                            
                        }
                    }
                    else{
                        if(day>28){
                            month++;
                            day=1;
                            
                        }
                    }
                    
                }
        System.out.print("Next date is:"+year+"-"+month+"-"+day);
    }
}

这道题需要先根据题目给出的条件判断输入日期是否合法,然后再求下一天的日期,这里需要考虑到这一天是否达到这一月的最后一天,以及这一月共有多少天,如果是二月份还需要是否是闰年,如果是闰年则二月份有29天;否则有28天,考虑完了月份还需要考虑年份,要考虑这一天是否是这一年的最后一天,如果是,则下一天日期变为一月一日,年份加一;

当时写这道题的时候对JAVA语法方面的内容还不是很熟悉,现在看来完全可以用数组(int[] mon_maxnum={0,31,28,31,30,31,30,31,31,30,31,30,31})来取代冗长的if里的条件;

 

  • 题目集三:7-3 定义日期类,要求我们定义一个类Date(Date类结构如下图所示)

  1. 当输入数据非法及输入日期不存在时,输出“Date Format is Wrong”;
  2. 当输入日期合法,输出下一天,格式如下:Next day is:年-月-日;
import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        int year = input.nextInt();
        int month = input.nextInt();
        int day = input.nextInt();
        Date date1 = new Date(year,month,day);
        if(date1.checkInputValidity()){
            date1.getNextDate();
            System.out.println("Next day is:"+date1.getYear()+"-"+date1.getMonth()+"-"+date1.getDay());
        }
        else
            System.out.println("Date Format is Wrong");
            
    }
}

class Date{
    private int year;
    private int month;
    private int day;
    private int[] mon_maxnum={0,31,28,31,30,31,30,31,31,30,31,30,31};
    
    Date(){
    }
    
    Date(int year,int month,int day){
        this.year=year;
        this.month=month;
        this.day=day;
    }
    
    public int getYear(){
        return year;
    }
    
    public void setyear(int year){
        this.year=year;
    }
    
    public int getMonth(){
        return month;
    }
    
    public void setMonth(int month){
        this.month=month;
    }
    
    public int getDay(){
        return day;
    }
    
    public void getDay(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(isLeapYear(this.year)){
            mon_maxnum[2]=29;
        }
        else{
            mon_maxnum[2]=28;
        }
        if(this.year>=1900&&this.year<=2000&&month>=1&&month<=12&&day>=1&&day<=mon_maxnum[month])
            return true;
        else
            return false;
    }
    
    public void getNextDate(){
        this.day++;
        if(this.day>mon_maxnum[this.month]){
            this.month++;
            this.day=1;
        }
        if(this.month>12){
            this.month=1;
            this.year++;
        }
    }
}

这道题我是一遍过的,毕竟计算量不大,仅仅只是下一天,需要考虑到这一天是否是这个月的最后一天,如果是,则下一天为下个月的第一天,还需要考虑到这个月是否是12月,如果是既12月又是最后一天,则下一天为下一年的1月1日。然后就是细节上的考虑,这里主要体现在对闰年的判断,对这道题来讲,因为只求下一天,所以只需考虑是否有2月29日。

  •   题目集三:7-4 日期类设计,要求参考7-3设计一个DateUtil,该类有三个私有属性year、month、day(均为整型数),其中,year∈[1820,2020] ,month∈[1,12] ,day∈[1,31],设计类图如下: 

  功能实现:

  1. 求下n天
  2. 求前n天
  3. 求两个日期相差的天数
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;
    private int month;
    private int day;
    private int[] mon_maxnum={0,31,28,31,30,31,30,31,31,30,31,30,31};
    
    DateUtil(){
    }
    
    DateUtil(int year,int month,int day){
        this.year=year;
        this.month=month;
        this.day=day;
    }
    
    public int getYear(){
        return year;
    }
    
    public void setyear(int year){
        this.year=year;
    }
    
    public int getMonth(){
        return month;
    }
    
    public void setMonth(int month){
        this.month=month;
    }
    
    public int getDay(){
        return day;
    }
    
    public void getDay(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(isLeapYear(this.year)){
            mon_maxnum[2]=29;
        }
        else{
            mon_maxnum[2]=28;
        }
        if(this.year>=1820&&this.year<=2020&&month>=1&&month<=12&&day>=1&&day<=mon_maxnum[month])
            return true;
        else
            return false;
    }
    
    public DateUtil getNextNDays(int n){
        //this.day=this.day+n;
        while(n>mon_maxnum[this.month]){
            if(isLeapYear(this.year)){
                mon_maxnum[2]=29;
            }
            else{
                mon_maxnum[2]=28;
            }
            n=n-mon_maxnum[this.month];
            this.month++;
            if(this.month>12){
                this.month=this.month-12;
                this.year++;
            }
            
        }
        this.day=this.day+n;
        if(this.day>mon_maxnum[this.month]){
            this.day=this.day-mon_maxnum[this.month];
            this.month++;
            if(this.month>12){
                this.month=this.month-12;
                this.year++;
            }
        }
        return new DateUtil(year,month,day);
    }
    
    public DateUtil getPreviousNDays(int n){
        this.day=this.day-n;
        while(this.day<=0){
            if(isLeapYear(this.year)){
                mon_maxnum[2]=29;
            }
            else{
                mon_maxnum[2]=28;
            }
            this.month--;
            if(this.month==0){
                this.year--;
                this.month=this.month+12;
            }
            this.day=mon_maxnum[this.month]+this.day;
        }
       return new DateUtil(year,month,day);
    }
    
    public boolean compareDates(DateUtil date){
        if(this.year>date.getYear())
            return true;
        else if(this.year==date.getYear()){
            if(this.month>date.getMonth())
                return true;
            else if(this.month==date.getMonth()){
                if(this.day>date.getDay())
                    return true;
                else if(this.day==date.getDay()){
                    return true;
                }else
                    return false;
            }else
                return false;
        }else
            return false;
    }
    
    public boolean equalTwoDates(DateUtil date){
        if(this.year==date.getYear()&&this.month==date.getMonth()&&this.day==date.getDay())
            return true;
        else
            return false;
    }
    
    public int getDaysofDates(DateUtil date){
        int n=0;
        n=n+mon_maxnum[this.month]-this.day;
        for(int i=1;this.month+i<13;i++){
            n=n+mon_maxnum[this.month+i];
        }
            while(this.year!=date.getYear()){
                if(this.year<date.getYear())
                    this.year++;
                else
                    this.year--;
                if(this.year==date.getYear())
                    break;
                if(isLeapYear(this.year))
                    n=n+366;
                else
                    n=n+365;
            }
        
             for(int i=1;i<date.getMonth();i++){
                n=n+mon_maxnum[i];
            }
            n=n+date.getDay();
        return n;
    }
    
    public String showDate(){
        String date="";
        date=year+"-"+month+"-"+day;
        return date;
    }
}

 

 这一题相当于是上一题的进阶版,在上一题的基础上改进,实现了求后n天的日期、前n天的日期和两个日期间相距多少天。我实现getDaysofDates方法的主要思想是:使第一个日期不断向第二个日期靠近,直至相等,同时用n不断加上相应增加的天数,这里重点在于日期的合法变化,要分月份和年份两个条件讨论;而实现getNextNDays、getPreviousNDays方法的主要思想是:n为天数,使n减少多少天,日期就相应增加多少天,直至n减少至0,而重点就在日期增加上,因为每个月的最大值不固定,每一年也不一定固定,所以这里就需要细心分析,分类讨论,判断这一年是否是闰年,判断这一月最大有多少天,进而来决定日期增加多少,n减少多少才能使日期合法增加。

踩坑心得

  1. 在题目集二:7-8 判断三角形类型中,在判断等腰直角三角形时,因为涉及到了无理数,所以数据运算一定存在一个误差无法消除 if(b==c&&(2*b*b-a*a)==0),之后规定当误差小于一个值时即为相等 if(b==c&&(2*b*b-a*a)*(2*b*b-a*a)<0.00001*0.00001),这才解决;
  2. 在题目集二:7-9 求下一天中,需要调取固定数值时,使用数组工具会更方便;
  3. 题目集三:7-4 日期类设计,这题中有个最大n值测试点花了很长时间才通过,这类测试点一般情况下是最容易被卡住的地方,这道题刚开始使一个正数加上n,所以导致超出了整型范围,后面把它改在后面加,才成功;可更多情况下是一些题目需要遍历数组或者列表(需要使用一个嵌套的双重for循环),这种情况下更容易超出范围,而且还不好解决,目前我能想到的就是如果需要排序,就使用现成的sort方法,如果要判断重复,可以使用Set来辅助判断;
    public DateUtil getNextNDays(int n){
            //this.day=this.day+n;这个是之前的错误
            while(n>mon_maxnum[this.month]){
                if(isLeapYear(this.year)){
                    mon_maxnum[2]=29;
                }
                else{
                    mon_maxnum[2]=28;
                }
                n=n-mon_maxnum[this.month];
                this.month++;
                if(this.month>12){
                    this.month=this.month-12;
                    this.year++;
                }
                
            }
            this.day=this.day+n;
            if(this.day>mon_maxnum[this.month]){
                this.day=this.day-mon_maxnum[this.month];
                this.month++;
                if(this.month>12){
                    this.month=this.month-12;
                    this.year++;
                }
            }
            return new DateUtil(year,month,day);
        }
  4. 在很多题目中,由于C语言习惯用System.out.printf()输出,可往往这样都通不过测试点,只能使用System.out.print()System.out.println(),下面是三者的一些区别:print为一般输出,同样不能保留精度格式转化,也不能换行输出; printf常用于格式转换,但需要注意不是换行输出,只用于精度转换; println为换行输出,不能用于格式化输出;                  
  5. 基本类型转换,有时候题目规定只能是单精度型或者只能是双精度型的数据结果才能通过测试点float w1=(float)(w/0.45359237)
  6. 误差判断时,大部分情况下要加一个平方,因为误差不仅是一个向左或向右的区间,误差是一个既向左又向右的区间,如while((g-m)>=0.00001)while((g-m)>=0.00001||(m-g)>=0.00001)
  7. 在题目集一:7-7 有重复的数据中,遇到了超时的问题,当时与其他同学讨论发现,使用ArrayList类进行排序,再遍历依旧超时,而使用Arrays类进行排序则不会超时,后面在查阅资料时发现,ArrayList是Array的复杂版本,ArrayList比Arrays的方法更多,功能更丰富,可以理解为Arrays是静态数组,而ArrayList是动态数组,而Sort 方法是在内部数组的基础上直接调用 Array 的对应方法,所以通常情况下:ArrayList的排序会比Arrays的排序时间要长;

     

改进建议

  1. 善用数组,在题目集二:7-9 求下一天中,使用数组来存储12个月的最大天数,对m进行判断时再通过数组下标来找出月份对应的天数,这会更加方便,而且易懂;
  2. 规范命名,尽可能写出英文全称,增加代码可读性;
  3. 多了解一些类的使用,比如String类,Arrays类,ArrayList类;
  4. 学习JAVA异常处理的相关内容,取代if判断;

总结

  三次题目集的训练,使我从零开始入门JAVA这门编程语言,使我对JAVA有了一个初步的了解,同时也对面对对象程序设计有了一个初步认识。面对对象程序设计与上学期的C语言(面向过程程序设计)不同,面向过程程序设计从逻辑上来看感觉更直接,而面向对象程序设计感觉更加抽象,更易于模块化。面向对象程序设计里,数据和数据上的操作是分离的,也就是对象和控制对象的方法,JAVA里的模块化主要体现在类上,类是一个抽象的模块,它包含了一系列对象及其方法,类的设计就是对现实世界的抽象化,所以面对对象程序设计也需要强大的抽象思维能力,在面对对象程序设计中,类的设计是重中之重,为了设计类,还需要探究类之间的关系,类之间的关系通常有关联、聚合、组合及继承,这也体现了面对对象程序设计的三大特点:封装性、继承性、多态性。

  通过三次作业,能够感觉到JAVA这门语言的强大,同时也能感觉到JAVA里的世界之大,目前我只学习到了它最基础的语法部分以及少量的类,JAVA自带了大量的类可以使用,这能大大方便我们解决问题。老师在上课时也带我们接触了一些从未听过的东西,比如JAVA里的集合框架,这些内容需要我们自己花大量时间去探究学习。