(1)前言: 面对对象程序设计的前三次pta作业,从第一次到第三次题量逐渐减少,难度逐渐上升。
第一次作业主要考察的知识点是输入输出,if-else和switch,一维数组等一些基础的语法,共8题,比较简单;
第二次作业主要考察的知识点是字符串,数组以及函数等,共5题,难度不高
第三次作业主要考察的知识点是面向对象的类的构造,共3题,因为要改变以前面向过程的编码方式,有一定难度
(2)题目设计与分析
7-8 判断三角形类型 (20 分)输入三角形三条边,判断该三角形为什么类型的三角形。
在一行中输入三角形的三条边的值(实型数),可以用一个或多个空格或回车分隔,其中三条边的取值范围均为[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”。
在这里给出一组输入。例如:
50 50 50.0结尾无空行
在这里给出相应的输出。例如:
Equilateral triangle结尾无空行
在这里给出一组输入。例如:
60.2 60.2 80.56结尾无空行
在这里给出相应的输出。例如:
Isosceles triangle结尾无空行
在这里给出一组输入。例如:
0.5 20.5 80结尾无空行
在这里给出相应的输出。例如:
Wrong Format结尾无空行 1.源码: 这道题主要是对于构成四种三角形的边的条件的判断
import java.util.*; public class Main{ public static void main(String[] args){ Scanner input=new Scanner(System.in); double num1=input.nextDouble(); double num2=input.nextDouble(); double num3=input.nextDouble(); if((num1>=1&&num1<=200)&&(num2>=1&&num2<=200)&&(num3>=1&&num3<=200)) { if((num1+num2<=num3)||(num1+num3<=num2)||(num3+num2<=num1)) System.out.println("Not a triangle"); else if(num1==num2&&num1==num3) System.out.println("Equilateral triangle"); else if((num1==num2&&num1*num1+num2*num2==num3*num3)||(num1==num3&&num1*num1+num3*num3==num2*num2)||(num3==num2&&num3*num3+num2*num2==num1*num1)) System.out.println("Isosceles right-angled triangle"); else if((num1==num2)||(num1==num3)||(num3==num2)) System.out.println("Isosceles triangle"); else if((num1*num1+num2*num2==num3*num3)||(num1*num1+num3*num3==num2*num2)||(num3*num3+num2*num2==num1*num1)) System.out.println("Right-angled triangle"); else System.out.println("General triangle"); } else System.out.println("Wrong Format"); } }
2.SourceMonitor的生成报表
3.踩坑心得
这个等腰直角三角形的测试点卡了很久很久,最后还是没有解决就提交作业了,后面问了一下同学才知道,如果输入1,1,√2,这三条边确实能构成等腰直角三角形,但是√2是一个无限循环小数,double型无法存储所有小数位,在进行判断的时候就需要误差控制
num1*num1+num2*num2==num3*num3这里的“=”就无法判断1,1,√2;改成
num1*num1+num2*num2-num3*num3<0.0005这样进行误差控制应该就能够通过测试点
4.改进建议
因为代码中用了很多if-else,&&和||导致代码复杂度过高,整个代码还是面对过程的思想,可以说是用Java语法写的c程序,同时代码读起来也很费劲,代码改进可以每个类型的三角形建一个类,减少if-else的使用来降低复杂度,
7-4 求下一天 (30 分)
输入年月日的值(均为整型数),输出该日期的下一天。 其中:年份的合法取值范围为[1820,2020] ,月份合法取值范围为[1,12] ,日期合法取值范围为[1,31] 。 注意:不允许使用Java中和日期相关的类和方法。
要求:Main类中必须含有如下方法,签名如下:
public static void main(String[] args);//主方法 public static boolean isLeapYear(int year) ;//判断year是否为闰年,返回boolean类型 public static boolean checkInputValidity(int year,int month,int day);//判断输入日期是否合法,返回布尔值 public static void nextDate(int year,int month,int day) ; //求输入日期的下一天
在一行内输入年月日的值,均为整型数,可以用一到多个空格或回车分隔。
在这里给出一组输入。例如:
2020 3 10结尾无空行
在这里给出相应的输出。例如:
Next date is:2020-3-11结尾无空行
在这里给出一组输入。例如:
2025 2 10结尾无空行
在这里给出相应的输出。例如:
Wrong Format结尾无空行
1.源码:
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(); if(checkInputValidity(year,month,day)) nextDate(year,month,day); else System.out.println("Wrong Format"); } public static boolean isLeapYear(int year) {//判断year是否为闰年,返回boolean类型; boolean isLeapYear=(year%4==0&&year%100!=0)||year%400==0; return isLeapYear; } public static boolean checkInputValidity(int year,int month,int day){//判断输入日期是否合法,返回布尔值 int format; if(1820<=year&&year<=2020){ if(month==1||month==3||month==5||month==7||month==8||month==10||month==12){ if(0<day&&day<=31) format=1; else format=0; } else if(month==4||month==6||month==9||month==11){ if(0<day&&day<=31) format=1; else format=0; } else if(month==2){ if((isLeapYear(year)&&day<=29&&0<=day)||((!isLeapYear(year))&&day<=28&&0<day)) format=1; else format=0; } else format=0; } else format=0; boolean checkInputValidity=(format==1); return checkInputValidity; } public static void nextDate(int year,int month,int day){ //求输入日期的下一天 if(isLeapYear(year)){ if((day==29&&month==2)||(day==30&&(month==4||month==6||month==9||month==11))||(day==31&&(month==1||month==3||month==5||month==7||month==8||month==10))) { month++; day=1; } else if(day==31||month==12){ year++; month=1; day=1; } else day++; } else{ if((day==28&&month==2)||(day==30&&(month==4||month==6||month==9||month==11))||(day==31&&(month==1||month==3||month==5||month==7||month==8||month==10))) { month++; day=1; } else if(day==31||month==12){ year++; month=1; day=1; } else day++; } System.out.println("Next date is:"+year+"-"+month+"-"+day); } }
2.SourceMonitor的生成报表
3.踩坑心得
日期的下一天特别要注意跨月,跨年的情况,跨月要注意2月在闰年平年的天数不同,在跨月判断的时候特别容易遗漏某个月份,还会有月份天数记错的时候,每个月份的天数还是需要先在草稿纸上记好,以免增加在代码完成后找bug的难度。
if((day==29&&month==2)||(day==30&&(month==4||month==6||month==9||month==11))||(day==31&&(month==1||month==3||month==5||month==7||month==8||month==10))) { month++; day=1; } else if(day==31||month==12){ year++; month=1; day=1; } else day++;
4.改进建议
在判断无效边界的时候,即判断月份和日期天数是否匹配的时候,可以设置两个数组,分别存贮平年和闰年的每一个月的天数,让天数和数组中的数据进行匹配,避免if-else,&&和||使用过多,或者可以使用switch-case进行判断,但是数组的方式会更简单一点,同样在求输入日期的下一天的函数中,也可以使用一个二维数组来判断跨月跨年的情况,这样比起用if-else嵌套更加简洁明了。
if(1820<=year&&year<=2020){ if(month==1||month==3||month==5||month==7||month==8||month==10||month==12){ if(0<day&&day<=31) format=1; else format=0; } else if(month==4||month==6||month==9||month==11){ if(0<day&&day<=31) format=1; else format=0; } else if(month==2){ if((isLeapYear(year)&&day<=29&&0<=day)||((!isLeapYear(year))&&day<=28&&0<day)) format=1; else format=0; } else format=0; }
7-5 求前N天 (30 分)
输入年月日的值(均为整型数),同时输入一个取值范围在[-10,10] 之间的整型数n,输出该日期的前n天(当n > 0时)、该日期的后n天(当n<0时)。
其中年份取值范围为 [1820,2020] ,月份取值范围为[1,12] ,日期取值范围为[1,31] 。
注意:不允许使用Java中任何与日期有关的类或方法。
在一行中输入年月日的值以及n的值,可以用一个或多个空格或回车分隔。
在这里给出一组输入。例如:
2018 6 19 8结尾无空行
在这里给出相应的输出。例如:
8 days ago is:2018-6-11结尾无空行
在这里给出一组输入。例如:
2018 6 19 -8结尾无空行
在这里给出相应的输出。例如:
-8 days ago is:2018-6-27结尾无空行
1.源码:
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(); int n=input.nextInt(); if(checkInputValidity(year,month,day,n)) nextnDate(year,month,day,n); else System.out.println("Wrong Format"); } public static boolean isLeapYear(int year) {//判断year是否为闰年,返回boolean类型; boolean isLeapYear=(year%4==0&&year%100!=0)||year%400==0; return isLeapYear; } public static boolean checkInputValidity(int year,int month,int day,int n){//判断输入日期是否合法,返回布尔值 int format; if(1820<=year&&year<=2020&&-10<=n&&n<=10){ if(month==1||month==3||month==5||month==7||month==8||month==10||month==12){ if(0<day&&day<=31) format=1; else format=0; } else if(month==4||month==6||month==9||month==11){ if(0<day&&day<=31) format=1; else format=0; } else if(month==2){ if((isLeapYear(year)&&day<=29&&0<=day)||((!isLeapYear(year))&&day<=28&&0<day)) format=1; else format=0; } else format=0; } else format=0; boolean checkInputValidity=(format==1); return checkInputValidity; } public static void nextnDate(int year,int month,int day,int n){ //求输入日期的n天前 if(-n<0){ if(isLeapYear(year)){ if(day<=n){ if(month==2||month==4||month==6||month==8||month==9||month==11) {month--; day=31-(n-day);} else if(month==5||month==7||month==10||month==12) {month--; day=30-(n-day);} else if(month==1) {year--; month=12; day=31-(n-day);} else {month--; day=29-(n-day);} } else day=day-n; } else{ if(day<=n){ if(month==2||month==4||month==6||month==8||month==9||month==11) {month--; day=31-(n-day);} else if(month==5||month==7||month==10||month==12){month--; day=30-(n-day);} else if(month==1) {year--; month=12; day=31-(n-day);} else {month--; day=28-(n-day);} } else day=day-n; } } else if(n<0){ if(isLeapYear(year)){ if((day-n)>29&&month==2) {month++;day=day-n-29;} else if((day-n)>31&&month==12) {year++;month=1;day=day-n-31;} else if((day-n)>30&&(month==4||month==6||month==9||month==11)) {month++;day=day-n-30;} else if((day-n)>31&&(month==1||month==3||month==5||month==7||month==8||month==10)) {month++;day=day-n-31;} else day=day-n; } else{ if((day-n)>28&&month==2) {month++;day=day-n-28;} else if(day-n>31&&month==12) {year++;month=1;day=day-n-31;} else if(day-n>30&&(month==4||month==6||month==9||month==11)) {month++;day=day-n-30;} else if(day-n>31&&(month==1||month==3||month==5||month==7||month==8||month==10)) {month++;day=day-n-31;} else day=day-n; } } else {day=day;month=month;year=year;} System.out.println(n+" days ago is:"+year+"-"+month+"-"+day); } }
2.SourceMonitor的生成报表
3.踩坑心得
首先就是求输入日期n天前的函数,我下意识的以为n为正数的时候,天数要增加,换句话就是日期的n天后,这个错误在我写完所有代码的时候才发现,导致这个函数中的代码要大幅度修改
public static void nextnDate(int year,int month,int day,int n){ //求输入日期的n天前
在修改的过程中因为if-else嵌套过多,很容易就混淆了,哪个if和哪个else配对,还有中括号的配对问题,导致找bug的过程异常困难,特别是中括号配对的问题,在还剩最后一个测试点无法通过的时候,确认了所有代码没有问题,且没有程序报错,终于发现了一个中括号写错了位置,这是在第一次修改由于变量判断错误导致的bug的过程中,修改代码导致的错误。
4.改进建议
判断无效边界的优化改进可以和7-4求日期下一天一样设置数组来降低复杂度,求输入日期的n天后的函数可以拆分成多个判断的函数,或者使用switch-case,避免if-else的多层嵌套。
7-2 定义日期类 (28 分)
定义一个类Date,包含三个私有属性年(year)、月(month)、日(day),均为整型数,其中:年份的合法取值范围为[1900,2000] ,月份合法取值范围为[1,12] ,日期合法取值范围为[1,31] 。 注意:不允许使用Java中和日期相关的类和方法,否则按0分处理。
要求:Date类结构如下图所示:
在一行内输入年月日的值,均为整型数,可以用一到多个空格或回车分隔。
在这里给出一组输入。例如:
1912 12 25结尾无空行
在这里给出相应的输出。例如:
Next day is:1912-12-26结尾无空行
在这里给出一组输入。例如:
2001 2 30结尾无空行
在这里给出相应的输出。例如:
Date Format is Wrong结尾无空行
1.源码:
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 date = new Date(year,month,day); if(date.checkInputValidity()==false) { System.out.println("Date Format is Wrong"); }else { date.getNextDate(); System.out.print("Next day is:"); System.out.print(date.getYear() + "-" + date.getMonth() + "-" + date.getDay()); } } } 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() { super(); } public Date(int year, int month, int day) { super(); 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 isLeapYear(int year) { if(( year % 100 != 0 && year % 4 == 0) || year % 400 == 0) { mon_maxnum[2] = 29; return true; }else { return false; } } public boolean checkInputValidity() { isLeapYear(this.year); if(this.year < 1900 || this.year > 2000|| this.month < 1 || this.month > 12 || this.day > mon_maxnum[this.month] || this.day < 1) return false; else return true; } public void getNextDate() { switch(this.month) { case 1: case 3: case 5: case 7: case 8: case 10: if(this.day == 31) { this.day = 1; this.month ++; }else this.day ++;break; case 12: if(this.day == 31) { this.day = 1; this.month = 1; this.year ++; }else this.day ++;break; case 4: case 6: case 9: case 11: if(this.day == 30) { this.day = 1; this.month ++; }else this.day ++; break; case 2: if(isLeapYear(this.year) == true && this.day == 29) { this.day = 1; this.month ++; } else if(this.day == 28) { this.day = 1; this.month ++; }else this.day ++; break; } } }
2.SourceMonitor的生成报表
3.踩坑心得
public void getNextDate()在这个方法中不知道该如何引用创建的Date类的对象的year,month和day,问了一下同学,学到了关键字super和this的用法,用this来进行调用
4.改进建议
暂时没有想到有更好的优化方法,希望能在作业互评中学习到其他同学中更好的编码方式。
7-3 一元多项式求导(类设计) (50 分)
编写程序性,实现对简单多项式的导函数进行求解。详见作业指导书。 OO作业3-3题目说明.pdf
在一行内输入一个待计算导函数的表达式,以回车符结束。
输出格式见输入输出示例。
在这里给出一组输入。例如:
-2* x^-2+ 5*x^12-4*x+ 12结尾无空行
在这里给出相应的输出。例如:
4*x^-3+60*x^11-4结尾无空行
在这里给出一组输入。例如:
2*x^6-0*x^7+5结尾无空行
在这里给出相应的输出。例如:
Wrong Format结尾无空行
1.源码 :无
2.踩坑心得:学数据结构时候的正则表达式没学好,这个题目一拿到手就蒙了,实在不会写,就只能写个static main了。
(3)总结
通过对本阶段三次题目集的综合性总结,我体会最深的就是面对对象的思想和编码方式,对于java语法比较熟悉了,我觉得我对于面对对象还不能完全掌握,很容易就会按照面对过程的思想去编码,这方面我还需要进一步强化,对教师、课程、作业、实验、课上及课下组织方式我觉得很好,希望老师能把每次上课ppt和一些文件能分享出来,一些上课没弄懂的东西,可以课后看一下。