前三次作业总结
面向对象程序设计第一阶段的学习已经告一段落了,总体而言,对于前三次作业,大概第一次作业最难(题目最多,最诡异),也有可能是刚刚接触java不熟悉导致的,就我个人而言,的确第一次较难,过去的已经过去,要总结并反思才能变强,所以下面开始我的总结
前言
三次作业,先吐槽一下为什么每次作业都这么独特,第一次作业的gps信息处理,看懂题目需要很久,找出隐含其中的信息,第二次就是题目测试点数据较大,第三次就是求n天考虑情况较多,吐槽完毕,步入正题。总的来说,前三次都是比较基础的题目,需要不断的积累和了解Java中的各种类的使用情况,做完这些题目之后感觉对于java有了一个别样的看法,这可跟”c语言“是不一样的。前言完毕,开始书写正文
设计与分析
第一次作业
这次作业前几题都是一些基础性的题目,只用一些基本的语法和方法,但第七题稍微转了下弯,见题
在一大堆数据中找出重复的是一件经常要做的事情。现在,我们要处理许多整数,在这些整数中,可能存在重复的数据。你要写一个程序来做这件事情,读入数据,检查是否有重复的数据。如果有,输出“YES”这三个字母;如果没有,则输出“NO”。
输入格式
你的程序首先会读到一个正整数n,n∈[1,100000],然后是n个整数。
输出格式
如果这些整数中存在重复的,就输出:
YES
否则,就输出:
NO
本题题目容易理解,但数据量较大,暴力的使用循环就会超时,而且在pta上使用Scanner的时间花费挺大,其次对于n个数的大小并没有给出范围,这就值得深深思考,最开始我准备用boolean数组标记数字(即创建一个boolean数组,将读取到的数作数组下标标记,只需要一次循环就行,只要重复出现,就可以判定结束),但是没有数据的大小范围,会出现问题,所以换一种方法,将数组进行排序,再遍历一次,只要判断相邻元素是否相等就可以完成这道题目,时间上也允许。
7-10 GPS数据处理
这个数据处理只需要使用字符串所提供的方法就可以完成,但有一点注意,所给的测试点都是与北京时间差8小时
第二次作业
7-1 长度质量计量单位换算
长度、质量的计量有多重不同的计算体系,有标准的国际单位制:千克与米,也有各个国家自己的计量方法如:磅、英寸;1磅等于0.45359237千克,1英寸等于0.0254米,请编写程序实现国际单位制与英制之间的换算。
输入格式:
两个浮点数,以空格分隔,第一个是质量(以千克为单位)、第二个是长度(以米为单位)。例如:0.45359237 0.0254。
输出格式:
两个浮点数,以空格分隔,第一个是质量(以磅为单位)、第二个是长度(以英寸为单位)。例如:1.0 1.0。
这个题目说使用浮点数,有一点要注意其实就是使用float,而不是double,还有输出的时候直接输出,不用用格式化输出
7-8 判断三角形类型
输入三角形三条边,判断该三角形为什么类型的三角形。
输入格式:
在一行中输入三角形的三条边的值(实型数),可以用一个或多个空格或回车分隔,其中三条边的取值范围均为[1,200]。
输出格式:
(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”。
这个题目的特别之处在于浮点数在计算机里表示是不完全精确的,所以判定直角三角形的时候需要用两个浮点数的差值小于一个小范围的数就可以通过。
第三次作业
7-3 定义日期类
定义一个类Date,包含三个私有属性年(year)、月(month)、日(day),均为整型数,其中:年份的合法取值范围为[1900,2000] ,月份合法取值范围为[1,12] ,日期合法取值范围为[1,31] 。
注意:不允许使用Java中和日期相关的类和方法,否则按0分处理。
要求:Date类结构如下图所示:

输入格式
在一行内输入年月日的值,均为整型数,可以用一到多个空格或回车分隔。
输出格式
- 当输入数据非法及输入日期不存在时,输出“Date Format is Wrong”;
- 当输入日期合法,输出下一天,格式如下:Next day is:年-月-日
输入样例
在这里给出一组输入。例如:
1912 12 25
输出样例
在这里给出相应的输出。例如:
Next day is:1912-12-26
这个题目的要求是比较直观的,类图都提供好了,只需要照着写就行了,需要注意的是对于求下天的函数,可以先直接让代表天数的那个date先加1,再对这个date处理和判断,这样就可以简化运算过程,特别需要关注的就是闰年平年之间的区别,代码如下
import java.util.Scanner; class Date{ private int year; //年份 private int month; //月份 private int day; //天数 private int[] mon_maxnum = new int[] {0,31,28,31,30,31,30,31,31,30,31,30,31}; //平年数组 private int[] mon_maxnum1 = new int[] {0,31,29,31,30,31,30,31,31,30,31,30,31}; //闰年数组 public Date() { //无参构造方法 } public Date(int year,int month,int day) { //含参构造方法 } public int getYear() //获取年份 { return year; } public int getMonth() { //获取月份 return month; } public int getDay() { //获取天数 return day; } public void setYear(int year) { //设置年份 this.year = year; } public void setMonth(int month) { //设置月份 this.month = month; } 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 void getNextDate(int n) { //求下一天 n是代表闰年或平年 day++; if(n==0&&day>mon_maxnum[month]) { day=1; if(month==12) { month=1; year++; } else month++; } if(n==1&&day>mon_maxnum1[month]) { day=1; if(month==12) { month=1; year++; } else month++; } } public void print() { //输出 System.out.printf("Next day is:%4d-%d-%d\n",year,month,day); } public boolean checkinputValidity(int n) { //检查输入数据合法性 if(year>2000||year<1900||month>12||month<1||day>31||day<1) return false; else if(n==1&&month==2&&day>29) return false; else if(n==0&&month==2&&day>28) return false; return true; } } public class Main{ //主类 public static void main(String[] args) { Scanner in = new Scanner(System.in); Date date = new Date(); date.setYear(in.nextInt()); date.setMonth(in.nextInt()); date.setDay(in.nextInt()); int n = 0; if(date.isLeapYear(date.getYear())) //判断闰平年和平年 n=1; if(date.checkinputValidity(n)) { date.getNextDate(n); date.print(); } else System.out.println("Date Format is Wrong"); //格式错误 } }
代码分析和圈复杂度图

7-4 日期类设计
参考题目3和日期相关的程序,设计一个类DateUtil,该类有三个私有属性year、month、day(均为整型数),其中,year∈[1820,2020] ,month∈[1,12] ,day∈[1,31] , 除了创建该类的构造方法、属性的getter及setter方法外,需要编写如下方法:
public boolean checkInputValidity();//检测输入的年、月、日是否合法
public boolean isLeapYear(int year);//判断year是否为闰年
public DateUtil getNextNDays(int n);//取得year-month-day的下n天日期
public DateUtil getPreviousNDays(int n);//取得year-month-day的前n天日期
public boolean compareDates(DateUtil date);//比较当前日期与date的大小(先后)
public boolean equalTwoDates(DateUtil date);//判断两个日期是否相等
public int getDaysofDates(DateUtil date);//求当前日期与date之间相差的天数
public String showDate();//以“year-month-day”格式返回日期值
应用程序共测试三个功能:
- 求下n天
- 求前n天
- 求两个日期相差的天数
本题在上一题的条件下,稍微扩展”亿“点点,就像我们老师说的:”求一天就会,求n天就不会了?“,没准就真不会。开始步入正题。对于本题,其本质和上一题是相似的,都需要通过day入手,求n天先让day加上n,直接按照闰年,平年所照应的月份天数一步一步减掉,直到最后在最终月份的天数以内,其中要注意的是年份和月份之间的变化,求前n天则和求下n天类似,区别在于一个加一个减,求前n天是减去n,再一步一步的加。对于求差值则需要先对哪个日期在前进行判断,先处理当前月份的日期到月底之间的差值,再一个月一个月去处理,方便一点,特别注意闰年和平年的2月的区别,当出了错时很大概率是因为这个 ,其中有个测试点是整型最大值,所以采用long较为合适方便
代码如下
import java.util.Date; import java.util.Scanner; class DateUtil{ private int year; //年份 private int month; //月份 private long day; //天数 后面有一个整型最大值测试点 所以此处使用long private int[][] mon_maxnum = new int[][] {{0,31,28,31,30,31,30,31,//闰平年月份 31,30,31,30,31}, {0,31,29,31,30,31,30,31,31,30,31,30,31}}; public DateUtil() { //无参构造方法 } public DateUtil(int year,int month,long day) { //含参构造方法 this.year=year; this.month = month; this.day = day; } public int getYear() //获取年份 { return year; } public int getMonth() { //获取月份 return month; } public long getDay() { //获取天数 return day; } public void setYear(int year) { //设置年份 this.year = year; } public void setMonth(int month) { //设置月份 this.month = month; } public void setDay(int day) { //设置日期 this.day = day; } public static boolean isLeapYear(int year) { //判断是否闰年 if((year%4==0&&year%100!=0)||year%400==0) return true; else return false; } public DateUtil getNextNDays(int a) { //取得下n天日期 int n = 0; int year1=year,month1=month; long day1=day; day1+=a; while(day1>mon_maxnum[n][month1]) { //从day入手逐渐将day变成30以内 n=0; if(DateUtil.isLeapYear(year1)) n=1; day1-=mon_maxnum[n][month1]; month1++; //月份一起变化 if(month1>12) { //控制年份 month1-=12; year1++; } } return new DateUtil(year1,month1,day1); } public void print() { //输出 System.out.printf("Next day is:%4d-%d-%d\n",year,month,day); } public boolean checkInputValidity() { //检测数据合法性 int n = 0; if(DateUtil.isLeapYear(year)) n = 1; if(year>2020||year<1820||month>12||month<1||day>31||day<1) return false; else if(n==1&&month==2&&day>29) return false; else if(n==0&&month==2&&day>28) return false; return true; } public DateUtil getPreviousNDays(int a) { //获取之前日期 int n = 0; int year1=year,month1=month; long day1=day; day1-=a; while(day1<0) //从day入手逐渐减小求解 { n=0; if(DateUtil.isLeapYear(year1)) n=1; if(month1==1) { month1=12; year1--; day1+=mon_maxnum[n][month1]; }else { month1--; day1+=mon_maxnum[n][month1]; } } return new DateUtil(year1,month1,day1); } public boolean compareDates(DateUtil date) { //比较两个日期的前后 long n = this.year*365+this.month*30+this.day; long n1 = date.year*365+date.month*30+date.day; if(n>n1) return true; else return false; } public boolean equalTwoDates(DateUtil date) { //判断两个日期是否为同一天 long n = this.year*365+this.month*30+this.day; long n1 = date.year*365+date.month*30+date.day; if(n==n1) return true; else return false; } public int getDaysofDates(DateUtil date ) { //求日期差值 int n = 0,a=0,h=0; if(this.year>date.year) { //判断哪个日期在前 if(DateUtil.isLeapYear(date.year)) //判断闰年 a=1; n+=(mon_maxnum[a][date.month]-date.day); //先求当前月份的差值 for(int i = date.month+1;i<=12;i++) { n+=mon_maxnum[a][i]; //直接加月份的天数 } for(int i = date.year+1;i<=this.year;i++) { a=0; if(DateUtil.isLeapYear(i)) //判断闰年 a=1; for(int j = 1;j<=12;j++) { //循环求相差的天数 n+=mon_maxnum[a][j]; if(i==this.year&&this.month-j==1) { h=1; break; } } if(h==1) break; } n+=this.day; } else if(date.year>this.year) { //判断哪个日期在前,方便求解 if(DateUtil.isLeapYear(this.year)) a=1; n+=(mon_maxnum[a][this.month]-this.day); //先处理当前月份,方便后面整月整月处理 for(int i = this.month+1;i<=12;i++) { n+=mon_maxnum[a][i]; } for(int i = this.year+1;i<=date.year;i++) { a=0; h=0; if(DateUtil.isLeapYear(i)) a=1; for(int j = 1;j<=12;j++) { n+=mon_maxnum[a][j]; if(i==date.year&&date.month-j==1) { h=1; break; } } if(h==1) break; } n+=date.day; }else { if(DateUtil.isLeapYear(year)) a=1; if(this.month>date.month) { //判断终止 n+=(mon_maxnum[a][this.month]-this.day); for(int i = date.month+1;i<this.month;i++) { n+=mon_maxnum[a][i]; } n+=this.day; }else if(month<date.month) { //判断终止 n+=(mon_maxnum[a][date.month]-date.day); for(int i = this.month+1;i<date.month;i++) { n+=mon_maxnum[a][i]; } n+=date.day; }else { if(day>date.day) n+=day-date.day; else n+=date.day-day; } } return n; } public String showDate() { //直接转换成字符串并连接方便后续输出 String s = year + ""; s = s + "-" + month + ""; s = s + "-" + day + ""; return s; } } 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) { 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) { 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); } } }
类的关系图

圈复杂度及代码分析

采坑心得
这个日期是真的难搞,特别是求差值,需要加许多判断,关键自己测试的时候出现问题,很难找,太多可能出现问题的地方了,如下:
1.对于闰年和平年的判断不准确
2 对于月份的12月 1月 日期的判断,年份的判断过多导致逻辑错误,而且往往难以筛选
3 求差值时,没有判断哪个日期在前,导致结果出错
写这些代码时最好时自己画个流程图,以防脑子突然抽风,搞混一些东西,最终导致错误,一定要写注释,当自己想要检查错误时,你就会发现原来注释是这么重要。
对于编程来说,比较两个实数如果是直接==是不够现实的,只能将两个实数进行相减然后小于某个特别小的数即可判定两个实数是否相等。在java中有相应的排序函数可以直接使用,大大提高效率,虽然不知道用的是什么算法,但时间复杂度是大大低于冒泡和选择的,所以有的时候java的一些方法和集合还是非常好用的,得赶紧学,不能停。
总结
通过这三次作业的学习,我对java的语法知识有了初步的了解,更好的理解的面向对象的编程思路,懂得程序设计的可用性以及代码编写的规范性!并且拥有了更好的代码执行经验。虽然前面三次作业是使用基本知识去完成问题,但依旧有难度,或许是我太菜了。第一次作业,大致是考你语法知识,除了有个别题目是有点奇怪之外其他都十几行代码就可以完成,主体作用就是引领你走上java和面向对象程序设计这条路,第二次作业和第一次作业差不多,都是语法和一些代码细节上的处理,总体难度不大,而第三次作业则是开始要设计类,正式步入面对对象程序设计这条道路,这种阶段性的学习确实可以给我们的学习留足时间,让我们能够更好的学习相关的知识,这点上老师也是煞费苦心啊,其实对于面向对象的学习还是需要自己去探索,老师只是一个引路人,在有限的课堂时间里只能教一部分,这就需要我们不断的去探索新知识。这三次作业也算是打击了我对于学习一门课程的信心,原来学习也是这么这么的痛苦。java一共有八种基本数据类型,String类是非常独特的,可以当成基本数据类型来用,也可以使用它的一些内部方法,使用起来极其的方便。还有其它类与类之间的关系,目前使用到的基本都是关联,也许后面会出现使用其它情况,还有单一职责原则这个东西真的不知道怎么去控制单一职责,获取会随着代码的熟练度变高之后去掌控它把。对于题目呢,希望能够多出点针对性强的题目,比如使用某个新奇的知识点去解决它。以上就是我的总结,希望未来能够变得越来越好,越来越强。

浙公网安备 33010602011771号