Blog作业总结01
一、前言:
此阶段能力有限,以下均为个人想法,共分为作业概况,设计与分析,踩坑心得,改进建议以及作业总结,仅供大家参考。
二、三次作业概况:
(1)第一次作业:
所含知识点:基本语法;创建数组;运用选择排序;运用Math.Abs函数计算;用相减小于1*10^(-9)来优化精度丢失的问题。
题量:较少
难度:较低
(2)第二次作业:
所含知识点:利用boolean判断是否闰年,日期是否合法;考虑闰年的不同月份的不同情况。
题量:中等
难度:较低
(3)第三次作业:
所含知识点:涉及到了类的封装性,多个类的写法;运用正则表达式;字符串截取的表达方式;动态数组的使用
题量:中等
难度:中等偏高
第一次题目集:7-8:
1、 设计与分析
(1)设计:
该作业的要求是实现三角形类型的判断。
首先设计将三角形的三条边分别存入数组中,用一个选择排序进行初次筛选,将最大最小边筛选出来,便于后续程序的书写,减少if语序的复杂度。
for(int j=0;j<2;j++) { for(int k=j+1;k<3;k++) { if(num[j]>num[k]) { double min=num[j]; num[j]=num[k]; num[k]=min; } } }
排完序后首先用if条件根据题目要求排除非法输入,其次利用三角形最基本的两边之和大于第三边的性质,(用判断出来的两个小边与最大边相比较即可,此处便体验到了排序后的便捷与准确)排除不是三角形的条件,接下来将等边等腰和等腰直角归为一类,剩下便是直角和一般三角形。
if(num[0]>=1&&num[0]<=200&&num[1]>=1&&num[1]<=200&&num[2]>=1&&num[2]<=200) { if((num[0]+num[1])>num[2]) { if(num[0]==num[1]&&num[0]==num[2]) System.out.println("Equilateral triangle");//3 else if(num[0]==num[1]||num[0]==num[1]||num[1]==num[2]) { if((Math. abs(num[2]*num[2]-num[1]*num[1]-num[0]*num[0]))<0.0000000001) System.out.println("Isosceles right-angled triangle");//4 else System.out.println("Isosceles triangle");//5 } else if((Math. abs(num[2]*num[2]-num[1]*num[1]-num[0]*num[0]))<0.0000000001) System.out.println("Right-angled triangle");//6 else System.out.println("General triangle");//7 } else System.out.println("Not a triangle");//2 } else System.out.println("Wrong Format");//1 } }
(2)分析:
根据PowerDesigner的类图显示,该题只有一个Main类,代码结构较为简单。

使用SourceMonitor对该函数的复杂度进行检测,结果如下:
SourceMonitor的生成报表:

Idea插件显示圈复杂度

由方法和类不多,但是圈复杂度很高,是因为这题用了多个if else语句,导致复杂度很高,代码状况复杂。
2、踩坑心得:
这题有两个坑容易入。
第一是数组的使用和排序:一开始,我一直是采用abc来表示三条边,也没有对abc进行排序,导致有很多情况都会出现误差,无法考虑周全。且一开始的if也全都是分开的,导致复杂度太高,还好后面稍微优化了一点。
第二个便是double的精度问题:由于Java中的小数计算不是那么准确,会出现精度丢失的问题,导致一开始在判断直角三角形的时候采用相减得0得方法并不可用,无法过测试点。故此采用Math. abs(num[2]*num[2]-num[1]*num[1]-num[0]*num[0]))<0.0000000001的方式进行判断(此处用绝对值保险起见)
3、改进建议:
为降低复杂度,if-else语句在某些情况可用switch-case结构或数组赋初始值的形式表达,使代码更为简洁,可读性更强。
第二次题目集:7-4:
1、 设计与分析
(1)设计:
该作业的要求输入年月日的值(均为整型数),输出该日期的下一天
首先设计非法输入,令boolean checkInputValidity = true;如果输入范围不在题目要求的范围内,在此注意闰年1月,2月,7月,8月和每月的边界情况,返回false,则输出("Wrong Format"),然后关闭程序(此处设定System.exit(0);有利于程序的终止)。
if(checkInputValidity(year,month,day)==false) { System.out.println("Wrong Format"); System.exit(0); } else nextDate(year,month,day); }
接下来就是判断是否闰年,这里利用闰年数a,a%4==0&&a%100!=0||a%400==0判断是否成立,为后续的日期数据的判断打下基础。
public static boolean isLeapYear( int a) {//判断year是否为闰年,返回boolean类型; boolean isLeapYear = false; if(a%4==0&&a%100!=0||a%400==0) { isLeapYear = true; return isLeapYear; } else { isLeapYear = false; return isLeapYear; } }
最后就是通过if语序进行严密的逻辑讨论:闰年2月到29号,平年到28号就进入下一月份;跨年12月到31号就结束一年进入下一年,并且月份变为1;再考虑大月和小月的问题。
if(isLeapYear(year)==true) { if(month==2) { if(day==29) { monthplus=month+1; dayplus=1; } else { monthplus=month; dayplus=day+1; } System.out.println("Next date is:"+year+"-"+monthplus+"-"+dayplus); } } if(isLeapYear(year)==false) { if(month==2) { if(day==28) { monthplus=month+1; dayplus=1; yearplus=year; } else { monthplus=month; dayplus=day+1; yearplus=year; } System.out.println("Next date is:"+yearplus+"-"+monthplus+"-"+dayplus); } } if(month==12) { if(day==31) { monthplus=1; dayplus=1; yearplus=year+1; } else { monthplus=month; dayplus=day+1; yearplus=year; } System.out.println("Next date is:"+yearplus+"-"+monthplus+"-"+dayplus); } if(month==1||month==3||month==5||month==7||month==8||month==10) { if(day==31) { monthplus=month+1; dayplus=1; } else { monthplus=month; dayplus=day+1; } System.out.println("Next date is:"+year+"-"+monthplus+"-"+dayplus); } if(month==4||month==6||month==9||month==11) { if(day==30) { monthplus=month+1; dayplus=1; } else { monthplus=month; dayplus=day+1; } System.out.println("Next date is:"+year+"-"+monthplus+"-"+dayplus); }
(2)分析:
根据PowerDesigner的类图显示,该题只有一个类,但利用了三个方法。

使用SourceMonitor对该函数的复杂度进行检测,结果如下:
SourceMonitor的生成报表:

此题复杂度较高,代码状况非常复杂,原因还是if语句过多。
2、踩坑心得:
这题有两个坑容易入,第一是if语句的关闭:一开始,未写System.exit(0),程序总是不能很好的关闭。
第二个是特殊月份的特殊情况没有想到:(这里pta的测试点起到了很大的作用)。其实此题题目并不难,总之一句话,这道题只要足够细心,一次过还是可以的。经过这题,我对闰年月份的判断熟练了不少。
3、改进建议:
第一,判断是否闰年没有应该写在最上面,体现逻辑的严密性,这里我将其写在第二块,复盘时觉得代码逻辑显得有点不够严谨。
第二,其实本题完全没必要写那么多的if和else,如果想到用int[] monthDate = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },并且把能和起来的条件用“||”和“&&”表示在一个if里面会降低很多复杂度,同时也会减少丢失考虑情况的误差(有的时候if-else用多了可能会导致代码长度超多题目设置而无法通过,所以还是在允许的情况下,想一种更为优化简洁的方式吧!)
7-5:
1、 设计与分析
(1)设计:
该作业的要求输入年月日的值(均为整型数),同时输入一个取值范围在[-10,10]之间的整型数n,输出该日期的前n天(当n > 0时)、该日期的后n天(当n<0时)。
此题和上题判断非法输入和是否闰年的方式一样,首先设计非法输入,令boolean checkInputValidity = true;如果输入范围不在题目要求的范围内,在此注意闰年1月,2月,3月初,7月,8月初,9月初和每月的边界,跨年的情况,返回false,则输出("Wrong Format"),然后关闭程序(此处设定System.exit(0);有利于程序的终止)。
if(checkInputValidity(year,month,day,n)==false) { System.out.println("Wrong Format"); System.exit(0); } else lastDate(year,month,day,n); }
接下来就是判断是否闰年
public static boolean isLeapYear( int a) {//判断year是否为闰年,返回boolean类型; boolean isLeapYear = false; if(a%4==0&&a%100!=0||a%400==0) { isLeapYear = true; return isLeapYear; } else { isLeapYear = false; return isLeapYear; } }
最后通过if语序进行判断(原谅我此处仍未优化):
闰年2月到29号,平年到28号,若输入为负就进入下一月份;
当3月初输入正数则回到2月,且日期是从29或28号开始相减;
8月和9月输入正数都是从上一月的31号开始减;
跨年12月到31号输入正数就结束一年进入下一年,并且月份变为1;
再考虑大月和小月的问题。
public static void lastDate(int year,int month,int day,int n) {//求输入日期的下一天 int dayplus=day-n; if(month==2&&isLeapYear(year)==true) { if(dayplus>29) { month=month+1; dayplus=dayplus-29; } else if(dayplus<1) { month=month-1; dayplus=31+dayplus; } else month=month; System.out.println(n+" days ago is:"+year+"-"+month+"-"+dayplus); return; } if(month==2&&isLeapYear(year)==false) { if(dayplus>28) { month=month+1; dayplus=dayplus-28; } else if(dayplus<1) { month=month-1; dayplus=31+dayplus; } else month=month; System.out.println(n+" days ago is:"+year+"-"+month+"-"+dayplus); return; } if(month==3&&isLeapYear(year)==true) { if(dayplus<1) { month=month-1; dayplus=29+dayplus; } else month=month; System.out.println(n+" days ago is:"+year+"-"+month+"-"+dayplus); return; } if(month==3&&isLeapYear(year)==false) { if(dayplus<1) { month=month-1; dayplus=28+dayplus; } else month=month; System.out.println(n+" days ago is:"+year+"-"+month+"-"+dayplus); return; } if(month==12) { if(dayplus>31) { month=1; year=year+1; dayplus=dayplus-31; } else if(dayplus<1) { month=month-1; dayplus=30+dayplus; } else month=month; System.out.println(n+" days ago is:"+year+"-"+month+"-"+dayplus); return; } if(month==1) { if(dayplus<1) { month=12; dayplus=31+dayplus; year=year-1; } else month=month; System.out.println(n+" days ago is:"+year+"-"+month+"-"+dayplus); return; } if(month==8) { if(dayplus>31) { month=month+1; dayplus=dayplus-31; } else if(dayplus<1) { month=month-1; dayplus=31+dayplus; } else month=month; System.out.println(n+" days ago is:"+year+"-"+month+"-"+dayplus); return; } if(month==5||month==7||month==10) { if(dayplus>31) { month=month+1; dayplus=dayplus-31; } else if(dayplus<1) { month=month-1; dayplus=30+dayplus; } else month=month; System.out.println(n+" days ago is:"+year+"-"+month+"-"+dayplus); return; } if(month==4||month==6||month==9||month==11) { if(dayplus>30) { month=month+1; dayplus=dayplus-30; } else if(dayplus<1) { month=month-1; dayplus=31+dayplus; } else month=month; System.out.println(n+" days ago is:"+year+"-"+month+"-"+dayplus); return; }
(2)分析:
根据PowerDesigner的类图显示,该题只有一个类,但利用了三个方法。

使用SourceMonitor对该函数的复杂度进行检测,结果如下:
SourceMonitor的生成报表:

此题同上题一样,复杂度高,代码状况非常复杂.
2、踩坑心得:
这题值得注意的是,当用户输入为负数时,实则是日期前推,输入为正时,则为减;经过了第四题,其他应该就没什么问题了。
3、改进建议:
同上一题一样,最好改为数组的形式,如果怕if语句中的条件太过复杂,还是可以选择拆开写的虽然复杂度相比较高,但是代码看起来较为易懂。
题目集三:7-2:
1、 设计与分析
(1)设计:
该作业的要求是定义一个类Date,包含三个私有属性年(year)、月(month)、日(day),均为整型数。
此题由提供的类图可知,需要我们重新构建一个新的Date类,Date date=new Date(year,month,day);并且对year month day 三个属性进行封装变为私有属性,同时构造有参和无参来进行传输数据,用get和set方法将其进行调用如下:
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}; Date(int year,int month,int day) { setYear( year); setMonth( month); setDay(day); } public void setYear(int year) { this.year=year; } public int getYear() { return 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; }
在搭建好结构后,接下来就是和上面两题差不多的思路,判断闰年,输入是否合法以及特殊月份特殊日期的判断。这里相比上面两道题较为优化的是day的数目直接存入数组中,if中的条件判断较为简单了。
public void getNextDate() { int monthplus,dayplus,yearplus; if(isLeapYear(year)==true&&month==2) { if(day==mon_maxnum[month]+1) {//day=29; monthplus=month+1; dayplus=1; } else { monthplus=month; dayplus=day+1; } System.out.println("Next day is:"+year+"-"+monthplus+"-"+dayplus); } if(isLeapYear(year)==false&&month==2) { if(day==mon_maxnum[month]) {//day=28 monthplus=month+1; dayplus=1; //yearplus=year; } else { monthplus=month; dayplus=day+1; //yearplus=year; } System.out.println("Next day is:"+year+"-"+monthplus+"-"+dayplus); } if(month==12) { if(day==mon_maxnum[month]) { monthplus=1; dayplus=1; yearplus=year+1; } else { monthplus=month; dayplus=day+1; yearplus=year; } System.out.println("Next day is:"+yearplus+"-"+monthplus+"-"+dayplus); } if(month==1||month==3||month==5||month==7||month==8||month==10) { if(day==mon_maxnum[month]) { monthplus=month+1; dayplus=1; } else { monthplus=month; dayplus=day+1; } System.out.println("Next day is:"+year+"-"+monthplus+"-"+dayplus); } if(month==4||month==6||month==9||month==11) { if(day==30) { monthplus=month+1; dayplus=1; } else { monthplus=month; dayplus=day+1; } System.out.println("Next day is:"+year+"-"+monthplus+"-"+dayplus); } }
(2)分析:
根据PowerDesigner的类图显示,直观地看出,该题涉及了两个类Date和Main,利用了多个方法:

使用SourceMonitor对该函数的复杂度进行检测,结果如下:
SourceMonitor的生成报表:

此题复杂度较高,代码状况非常复杂。
2、踩坑心得:
该类题对于一开始接触新增类的小白来说,写代码的路途确实有点坎坷,好在第三次作业第一题有较为明了的提示,代码搭建的过程相比第一次较为顺畅,只不过在此题目的要求下没办法采用if的简单逻辑角度进行判断,而要采用 int [] mon_maxnum= new int[] {0,31,28,31,30,31,30,31,31,30,31,30,31};day==mon_maxnum[month]来计算yearplus、monthplus和dayplus的数据变化。
3、改进建议:
同样还是在大块的if-else语句中进行优化和修改吧(实话实说,提交的时候,已经好几次提醒超出代码长度了),至于其他的修改及方式,本人还在努力学习当中,我相信通过日后的学习与练习会使代码更加优化简洁的。
7-3:
1、 设计与分析
(1)设计:
该题的要求是编写程序性,实现对简单多项式的导函数进行求解。同时还要满足以下要求
- 当某一项为“0”时,则该项不需要显示,但如果整个导函数结果为“0”时,则显示为“0”;
- 当输出结果第一项系数符号为“+”时,不输出“+”;
- 当指数符号为“+”时,不输出“+”;
- 当指数值为“0”时,则不需要输出“x^0”,只需要输出其系数即可。
这道题的想法都包括在心得体会里了,话不多说,直接附代码:
import java.util.ArrayList; import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { Array array=new Array(); array.array(); } } class Array { String string; int i,j; void array() { Scanner input = new Scanner(System.in); string=input.nextLine(); String [] str=string.split("");//分割字符串(但不完全保留) ArrayList<String> num = new ArrayList<>(); Pattern p1 = Pattern.compile("([+-]?x\\^)|(\\*x\\^)|(\\*x)|[+-]{1}x|^x[+-]{1}\r\n"); string=string.replaceAll("\\s*",""); Matcher m1 = p1.matcher(string); int count=-1; while(m1.find()){ count=count+1; num.add(m1.group()); } ArrayList<String> mum = new ArrayList<>(); Pattern p2 = Pattern.compile("[+-]?\\d+"); Matcher m2 = p2.matcher(string); int um=-1; while(m2.find()){ um=um+1; mum.add(m2.group()); } if(string.indexOf("+0*")!=-1||string.indexOf("^0")!=-1||string.indexOf("-0*")!=-1) { System.out.println("Wrong Format"); System.exit(0); } else if(num.size() == 0 && mum.size() == 1) { System.out.println("0"); } else { int number1 = 0; int number2 = 0; for(i=0,j=0;i < num.size();i++,j++) { if(num.get(i).equals("*x^")) { number1=Integer.parseInt(mum.get(j))*Integer.parseInt(mum.get(j+1)); number2=Integer.parseInt(mum.get(j+1))-1; if(number1 > 0 && i != 0) System.out.print("+"); System.out.print(number1 + "*x^" + number2); j++; } else if(num.get(2).equals("*x")) { number1=Integer.parseInt(mum.get(4)); if(number1 > 0 && i != 0) System.out.print("+"); System.out.print(number1); } } } } }
(2)分析:
根据PowerDesigner的类图显示,直观地看出,该题涉及了两个类Array和Main,其次在Array中利用了多个方法:
使用SourceMonitor对该函数的复杂度进行检测,结果如下:
SourceMonitor的生成报表:

此题复杂度较高,代码状况较为复杂。
2、踩坑心得:
这道题开头老师就交给我们一个小任务——学习正则表达式,但当我学完之后我却发现,将其内容串通起来好像还是有点复杂的。一开始我用想过用split方法暴力解决,但是却无法切出我想要的数据,后来我用\\*|\\^|\\+|[a-z]|\\d+|-进行切割,数字和字符都能一项一项的切出来,却无法切开负数。经过讨论,发现这样切出一项一项的好像并没有什么用,于是用([+-]?x\\^)|(\\*x\\^)|(\\*x)|[+-]{1}x|^x[+-]{1}\r\n"将其切成一个个的子项进行求导的计算。
同时,由于课堂上老师提到了一次动态数组,我就在此利用上了,但是因为才学浅薄,还未完全学会动态数组的用法,为后续数据穿插的代码书写造成了一定的困扰和麻烦。
3、改进建议:
我认为这里对于新手小白来说,存储数据还是用正常的数组会比较好调用(当然,大佬们可跳过这条建议)同时,由于求导的函数表达式有可能出现大数,还是用BigInteger会比较稳妥。
三、作业总结:
1、第一次作业虽然题目量较大,但做起来还是挺顺畅,只要会Java的基本格式书写就没什么问题。
2、第二次作业主要是通过严密的逻辑来考虑现实生活中,平年润年对于不同月份日期加减的限制要求,从而选择一个正确且便捷的方式进行加减计算,整体来说,除了要注意复杂度,其他并没有什么太大的问题。
3、第三次作业,别看只有三道题,却困住了许多同学,首先是前两到类的增加以及封装性,但根据题目的提示,再结合书上的知识点,在搭好所要求的框架后,其他问题就迎刃而解了。当然,这里涉及到的新知识点还挺多,对这两道题进行深度学习和理解对于后续的学习还是很有必要的。重点是第三题,首先是正则表达式的书写就让我有点犯难,其次就是选择分割的位置的选取以及动态数组熟练应用的问题。
4、总而言之,经过这三次大作业,我发现自己的知识储备量还远远不够,在后续的学习中,我会与同学多多讨论,查找有关资料对Java及其语法的使用进行更深入的认知与学习,同时,要对书本有更深刻的解读。
2021-04-04

浙公网安备 33010602011771号