PTA OOP第一次总结性作业
Posted zxt887957
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PTA OOP第一次总结性作业相关的知识,希望对你有一定的参考价值。
南昌航空大学 软件学院 222019班 朱晓天
关于OOP
这个学期,我们也是第一次接触到面向对象的课程,上个学期的程序设计课,我们也是学了python这门语言,但是上个学期我们更多的是学习语法和锻炼编程的能力,对于面向对象的概念只是少有提及,所以第一次看见有面向对象这门课的时候我还是一脸懵的状态,也是在之后逐渐了解了面向对象与之前所学的C语言的区别。
在java这个语言之中,用的并不是像C语言中的函数,而是运用类和方法,在语法上有很多与C语言相似的地方,同时也在C语言的基础上加入了很多新的语法,新的功能,在很多实际情况的处理上都比C语言方便很多。
关于PTA作业
前三周的时间里,我们总共完成了三次的PTA训练作业,题目量都不算多,这三次PTA作业,每一次都有不一样的收获,我主要挑我在写的时候遇到困难或者有思考价值的题目讲讲。
OOP第一次训练集
第一次PTA联系更多的是让我们自学并且熟悉java的语法,主要考察我们对字符串的处理。
7-7 有重复的数据
在一大堆数据中找出重复的是一件经常要做的事情。现在,我们要处理许多整数,在这些整数中,可能存在重复的数据。你要写一个程序来做这件事情,读入数据,检查是否有重复的数据。如果有,输出“YES
”这三个字母;如果没有,则输出“NO
”。
import java.util.*; public class Main public static void main(String[] args) Scanner input=new Scanner(System.in); int n=input.nextInt(); int a[]=new int[n]; boolean t=true; for(int i=0;i<n;i++) a[i]=input.nextInt(); Arrays.sort(a); for(int i=0;i<n-1;i++) if(a[i]==a[i+1]) t=false; break; if(t==true) System.out.print("NO"); else System.out.print("YES");
这一道题相对比较简单,只要把判断重复的逻辑想明白这道题就可以迎刃而解了。我在写的时候使用了Java中的Arrays类的sort方法对数组进行排序,然后使用遍历数组的方式检查相邻的元素是否相等。如果存在相等的元素,则将标记设置为false并退出循环。最后根据标记的值输出相应的结果。
但是在一开始写这道题的时候遇到了几个测试点没过,都是超时和内存超限的问题,后来想到利用Arrays.sort()对数字进行排序,就可以避免在程序中使用嵌套循环多次遍历来判断重复而导致内存超限和超时的问题了。
7-10 GPS数据处理
NMEA-0183协议是为了在不同的GPS(全球定位系统)导航设备中建立统一的BTCM(海事无线电技术委员会)标准,由美国国家海洋电子协会(NMEA-The National Marine Electronics Associa-tion)制定的一套通讯协议。GPS接收机根据NMEA-0183协议的标准规范,将位置、速度等信息通过串口传送到PC机、PDA等设备。
NMEA-0183协议是GPS接收机应当遵守的标准协议,也是目前GPS接收机上使用最广泛的协议,大多数常见的GPS接收机、GPS数据处理软件、导航软件都遵守或者至少兼容这个协议。
NMEA-0183协议定义的语句非常多,但是常用的或者说兼容性最广的语句只有$GPGGA、$GPGSA、$GPGSV、$GPRMC、$GPVTG、$GPGLL
等。
其中$GPRMC
语句的格式如下:
$GPRMC,024813.640,A,3158.4608,N,11848.3737,E,10.05,324.27,150706,,,A*50
这里整条语句是一个文本行,行中以逗号“,”隔开各个字段,每个字段的大小(长度)不一,这里的示例只是一种可能,并不能认为字段的大小就如上述例句一样。
- 字段0:
$GPRMC
,语句ID,表明该语句为Recommended Minimum Specific GPS/TRANSIT Data(RMC)推荐最小定位信息 - 字段1:UTC时间,hhmmss.sss格式
- 字段2:状态,A=定位,V=未定位
- 字段3:纬度ddmm.mmmm,度分格式(前导位数不足则补0)
- 字段4:纬度N(北纬)或S(南纬)
- 字段5:经度dddmm.mmmm,度分格式(前导位数不足则补0)
- 字段6:经度E(东经)或W(西经)
- 字段7:速度,节,Knots
- 字段8:方位角,度
- 字段9:UTC日期,DDMMYY格式
- 字段10:磁偏角,(000 - 180)度(前导位数不足则补0)
- 字段11:磁偏角方向,E=东W=西
- 字段16:校验值
这里,*
为校验和识别符,其后面的两位数为校验和,代表了$
和*
之间所有字符(不包括这两个字符)的异或值的十六进制值。上面这条例句的校验和是十六进制的50,也就是十进制的80。
提示:^
运算符的作用是异或。将$
和*
之间所有的字符做^
运算(第一个字符和第二个字符异或,结果再和第三个字符异或,依此类推)之后的值对65536取余后的结果,应该和*
后面的两个十六进制数字的值相等,否则的话说明这条语句在传输中发生了错误。注意这个十六进制值中是会出现A-F的大写字母的。另外,在Java语言中,如果你需要的话,可以用Integer.parseInt(s)
从String
变量s
中得到其所表达的整数数字;而Integer.parseInt(s, 16)
从String
变量s
中得到其所表达的十六进制数字
现在,你的程序要读入一系列GPS输出,其中包含$GPRMC
,也包含其他语句。在数据的最后,有一行单独的END
表示数据的结束。
你的程序要从中找出$GPRMC
语句,计算校验和,找出其中校验正确,并且字段2表示已定位的语句,从中计算出时间,换算成北京时间。一次数据中会包含多条$GPRMC
语句,以最后一条语句得到的北京时间作为结果输出。
你的程序一定会读到一条有效的$GPRMC
语句。
import java.util.*; public class Main public static void main(String[] args) Scanner input = new Scanner(System.in); int hh = 0, mm = 0, ss = 0; String str = input.nextLine(); while (!str.equals("END")) int index = str.indexOf(\',\'); index = str.indexOf(\',\', index + 1); if (str.substring(0, 6).compareTo("$GPRMC") == 0 && str.char(index + 1) == \'A\') int checkNum = str.char(1); for (int i = 2; str.char(i) != \'*\'; i++) checkNum ^= str.char(i); checkNum %= 65536; int givenNum = Integer.parseInt(str.substring(str.length() - 2, str.length()), 16); if (checkNum == givenNum) hh = (str.char(7) - \'0\') * 10 + (str.char(8) - \'0\'); mm = (str.char(9) - \'0\') * 10 + (str.char(10) - \'0\'); ss = (str.char(11) - \'0\') * 10 + (str.char(12) - \'0\'); hh = (hh + 8) % 24; str = input.nextLine(); if (hh < 10) System.out.print(0); System.out.print(hh + ":"); if (mm < 10) System.out.print(0); System.out.print(mm + ":"); if (ss < 10) System.out.print(0); System.out.print(ss);
OOP第二次训练集
相比于第一次的训练集,第二次训练集就并不单纯的是让我们熟悉语法那么简单了,这一次作业开始需要我们有一定的逻辑思维能力了。
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”。
import java.util.*; 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 if(a+b<=c||a+c<=b||b+c<=a) System.out.print("Not a triangle"); else if(a==b&&b==c) System.out.print("Equilateral triangle"); else if(a==b&&a*a+b*b-c*c<0.1||c==b&&c*c+b*b-a*a<0.1||a==c&&a*a+c*c-b*b<0.1) System.out.print("Isosceles right-angled triangle"); else if(a==b&&b!=c&&a*a+b*b!=c*c||b==c&&b!=a&&c*c+b*b!=a*a||a==c&&a!=b&&a*a+c*c!=b*b) System.out.print("Isosceles triangle"); else if(a!=b&&a*a+b*b==c*c||c!=b&&c*c+b*b==a*a||a!=c&&a*a+c*c==b*b) System.out.print("Right-angled triangle"); else System.out.print("General triangle");
这道题目主要就是考察我们的选择结构的思维能力,同时也考察了一下三角形的判断,在三角形判断和if else语句的运用上面我相信一般人都不会出什么错误,但是在我写完信心满满地提交的时候,有两个测试点显示的是答案错误,判断等腰直角三角形的答案错误了,我也是立马检查了判断等腰直角三角形的代码,但是我翻来覆去地检查了好多次,也没有找到任何逻辑或者输出上的问题,而这两个”答案错误“也一直困扰了我很久,之后我也是问了很多人才得知,是判断条件中数据处理时出现的问题,计算机并不能进行精密的计算,计算出来的数据都会有一定的误差,所以我们需要把这个误差计算进去(划重点),所以在把0.1的误差计算进去后,答案也就对了。
OOP第三次训练集
第三次训练集又是在第二次训练集的基础上增加了难度,需要我们有更强的逻辑思维能力,并且要有更多的java语言知识的储备。
7-3 定义日期类
定义一个类Date,包含三个私有属性年(year)、月(month)、日(day),均为整型数,其中:年份的合法取值范围为[1900,2000] ,月份合法取值范围为[1,12] ,日期合法取值范围为[1,31] 。注意:不允许使用Java中和日期相关的类和方法,否则按0分处理。
import java.util.*; 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 da = new Date(); if(da.checkInputValidity(year,month,day)==false) System.out.print("Date Format is Wrong"); else da.getNextDate(year,month,day); class Date private int year; private int month; private int day; 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) boolean LeapYear = false; if(year%4==0&&year%100!=0||year%400==0) LeapYear = true; return LeapYear; public boolean checkInputValidity(int year,int month,int day) if(year<1900||year>2000||month<1||month>12||day<1||day>31) return false; else if(month==2&&day>mon_maxnum[month]&&isLeapYear(year)==false) return false; else if(month==2&&day>29&&isLeapYear(year)==true) return false; else if((month==4||month==6||month==9||month==11)&&day>mon_maxnum[month]) return false; else return true; public void getNextDate(int year,int month,int day) if(month==12) if(day==31) day=1; month=1; year+=1; else day+=1; else if(month==1||month==3||month==5||month==7||month==8||month==10) if(day==31) month+=1; day=1; else day+=1; else if(month==4||month==6||month==9||month==11) if(day==30) day=1; month+=1; else day+=1; else if(month==2) if(isLeapYear(year)==true) if(day==29) month+=1; day=1; else day+=1; else if(isLeapYear(year)==false) if(day==28) month+=1; day=1; else day=1; System.out.print("Next day is:"+year+"-"+month+"-"+day);
从这一道题开始,就考察了我们构造方法的知识和类与方法之间的关系、多个类的程序的语法,这一道题的难度并不是特别大,我的主要思路就是在判断下一天的时候,将跨年、跨月(2月闰年、非闰年跨月)这种特殊的情况单独拿出来判断,然后只是天数更改的总的进行判断,只要逻辑比较清晰,这道题很快就可以做得出来。
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天
- 求两个日期相差的天数
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);
我的答案:
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; public DateUtil() public 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 setDay(int day) this.day = day; public boolean checkInputValidity() if(year<1820||year>2020||month<1||month>12||day<1||day>31) return false; else if(month==2&&day>28&&this.isLeapYear(this.getYear())==false) return false; else if(month==2&&day>29&&this.isLeapYear(this.getYear())==true) return false; else if((month==4||month==6||month==9||month==11)&&day>30) return false; else return true; public boolean isLeapYear(int year) if((year%4==0&&year%100!=0)||(year%400==0)) return true; else return false; public DateUtil getNextNDays(int n) int[] mon_maxnum = new int[]0,31,28,31,30,31,30,31,31,30,31,30,31; while(n!=0) if(month==12&&day==mon_maxnum[month]) year++; month=1; day=1; n-=1; else if(month==2&&day<29&&this.isLeapYear(year)==true) day++; n-=1; else if(month==2&&day==29&&this.isLeapYear(year)==true ) day=1; month=3; n-=1; else if(month==2&&day==28&&this.isLeapYear(year)==false ) day=1; month=3; n-=1; else if(day==mon_maxnum[month]) day=1; month++; n-=1; else day++; n-=1; return this; public DateUtil getPreviousNDays(int n) int[] mon_maxnum = new int[]0,31,28,31,30,31,30,31,31,30,31,30,31; int year1=year; int month1=month; int day1=day; while(n!=0) if(month1==1&&day1==1) month1=12; year1--; day1=mon_maxnum[month1]; n-=1; else if(month1==3&&day1==1&&this.isLeapYear(year1)==true) month1=2; day1=29; n-=1; else if(month1==2&&day1<=29&&day1>1&&this.isLeapYear(year1)==true) day1--; n-=1; else if(month1==3&&day1==1&&this.isLeapYear(year1)==false) month1=2; day1=28; n-=1; else if(day1==1) month1-=1; day1=mon_maxnum[month1]; n-=1; else day1-=1; n-=1; DateUtil beforedate = new DateUtil(year1,month1,day1); return beforedate; public boolean compareDates(DateUtil date) if(this.year > date.getYear()) return true; else if(this.year == date.getYear() && this.month > date.getMonth()) return true; else if(this.year == date.getYear() && this.month == date.getMonth() && this.day > date.getDay()) return true; 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 days=0; DateUtil fromDate = new DateUtil(this.year,this.month,this.day); int[] mon_maxnum = new int[]0,31,28,31,30,31,30,31,31,30,31,30,31; if(this.equalTwoDates(date)==true) days=0; else if(this.compareDates(date)==true) while(this.equalTwoDates(date)==false) if(fromDate.month==1&&fromDate.day==1) fromDate.month=12; fromDate.year--; fromDate.day=mon_maxnum[fromDate.month]; days+=1; else if(fromDate.month==3&&fromDate.day==1&&this.isLeapYear(fromDate.year)==true) fromDate.month=2; fromDate.day=29; days+=1; else if(fromDate.month==2&&fromDate.day<=29&&fromDate.day>1&&this.isLeapYear(fromDate.year)==true) fromDate.day--; days+=1; else if(fromDate.month==3&&fromDate.day==1&&this.isLeapYear(fromDate.year)==false) fromDate.month=2; fromDate.day=28; days+=1; else if(fromDate.day==1) fromDate.month-=1; fromDate.day=mon_maxnum[fromDate.month]; days+=1; else fromDate.day-=1; days+=1; else if(this.compareDates(date)==false) while(this.equalTwoDates(date)==false) if(date.month==1&&date.day==1) date.month=12; date.year--; date.day=mon_maxnum[date.month]; days+=1; else if(date.month==3&&date.day==1&&this.isLeapYear(date.year)==true) date.month=2; date.day=29; days+=1; else if(date.month==2&&date.day<=29&&date.day>1&&this.isLeapYear(date.year)==true) date.day--; days+=1; else if(date.month==3&&date.day==1&&this.isLeapYear(date.year)==false) date.month=2; date.day=28; days+=1; else if(date.day==1) date.month-=1; date.day=mon_maxnum[date.month]; days+=1; else date.day-=1; days+=1; return days; public String showDate() String str = year+"-"+month+"-"+day; return str;
这道题是我们这三次的作业中难度最大的一道题,因为求下n天和前n天有可能会跨过很多年,而跨的这些年中有很大可能会有闰年,在计算上面就比较麻烦,我采用的方法比较笨,我选择的是从输入的日期开始,经历n天,每经过一天,n减一,当n等于0的时候循环结束,这里我是用了whlie语句实现循环,在这里,我们需要考虑的情况也多了一些,但是主要还是注意跨年和闰年、非闰年的二月。之后的计算两个日期相隔的天数的时候,我用了和之前正好相反的方法,在判断了两个日期的大小后,从大的那一天开始,一天天往下减,每减一天,相隔时间天数加一,直到两个日期相等,这里同样也是用whlie语句来实现循环。这种一天天遍历的方法虽然比较笨,但是只要把逻辑理清楚之后,不容易犯错误,属于条理性比较强的方法。
改进分析:
在这道题提交完之后,我也想了想有没有比较”聪明“一点的方法来实现程序,我也参考了别人的方法与思路,可以不用一天一天地加,可以选择一年一年的加,这样只需要判断是不是闰年,是的话就设366天,不是就设365天,然后将n减去一年的天数,如果大于0,year减一,但是小于0的话就要判断n加当前的天数是否大于当前月的天数,大于的话月数加一,这样做的话就要用到两层whlie的嵌套循环。这种方法的条理性就不是特别地强,所以在写程序的时候很可能会有很多的情况会漏掉,但是如果自己的思维足够敏捷、足够跳脱,这种方法会更加高效。
总结
这三次的作业总体来说难度不大,题目量也不多,但是有些题目还是需要静下心来思考才能做好。通过这三次的PTA作业,我也基本能够掌握java语言中对字符串的处理方法,同时也知道了很重要的知识——计算机的计算都会有误差,并不精准。这段时间的作业,也让我发现了自己最大的问题,那就是思维比较固化,写的很多程序的思路大多都是按部就班的那种,并没有那种跳脱的思维,在很多时候,我都得从最底层开始构造程序的大体框架,没办法做到看一步就能想到后面多步,所以我的思维能力还是很需要培养的。这三次的作业,也基本帮助我们搭建了一个最基本的java语言的框架,而且从第一次的作业中,我能明显地感觉到java语言中像HashSet、StringBuffer这种容器的方便,很多在C语言中可能要几十行代码才能解决的事情在java中只要用一个方法就可以解决。所以我也希望老师能够在后续的课程里多教一点好用的容器(毕竟有些时候自己看不懂捏,有些时候看懂了也不会用捏),并且多给我们一些锻炼思维的机会。
以上是关于PTA OOP第一次总结性作业的主要内容,如果未能解决你的问题,请参考以下文章