题目集1~3的总结性Blog

发布时间 2023-03-25 22:43:07作者: maomaomaom

1. 前言:

题目集分析:

       题目集1题量为十二道题,因为是第一次使用Java编程,所以还不太熟练,题目1是三次题目集中分数最低的。题目集1的知识点偏向于对基本知识的考核,比如题目中多次出现对循环、选择结构、字符串等,其中第十题和第十一题是题目集1中的难度担当,光是题目就一大串,其中第十题设计到十六进制的转化和字符串的相关知识。

       题目集2题量为九道题,有了第一次的编程经验,第二次题目集编程起来犯的错误更少了。题目集2的侧重考察知识点是选择结构,在题目3、4、5、8、9有着明显的体现,需要设计一系列的if-else来判断不同的情况。题目集2的难度担当是第八题和第九题,第八题中对不同三角形的判断条件往往会忽视浮点数不能精确计算这一局限而无法通过直角三角形的测试点;第九题求下一天需要注意到许多的细节,比如对年份是否为闰年的判断和该年中二月份的天数,由于当时未想到将一年的不同月份的天数存放在一个数组中,导致编程过程过于繁琐了。

       题目集3题量为四道题,虽然是三次题目集中题量最少的,但却是三次题目集中最难的一次,尤其是第四题,从它44的分值就能感受到难度。第三次题目集与前两次题目集的涉及知识点不同,第三次题目集考察了对类的定义、构造方法等。每道题都需要定义类,并且设计方法。第三题与第二次题目集的第九题相似,这次我使用了数组来存放一年中不同月份的天数,这样避免了使用if-else语句来确定天数,代码看起来更加简洁高效。题目集3的难度担当是第四题,第四题完成三个功能:

求下n天、求前n天、求两个日期相差的天数

       其中完成求下n天功能是最难的,求上n天与其相似,编写并不复杂。

 

2. 设计与分析:

题目3的7-3:

      这题需要设计一个Date类包含三个私有属性年(year)、月(month)、日(day)。在PowerDesigner的相应类图包含main类和Date类

 

       在Date类中包含三个私有属性year、month、day和一个属性mon_maxnum来存放一年中的不同月份中的不同的天数,isLeapYear()方法用来判断年份是否为闰年;checkInputValidity()方法用来判断年份是否有效;getNextDate()方法用来输出下一天。这题的难点在与闰年与平年中的二月份天数不同,需要在编程的过程中时刻注意,我使用了if语句来判断,当年份为闰年使对mon_maxnum[2]进行重新赋值。还有就是在checkInputValidity()方法中需要注意在二月份时在闰年或在平年有不同的判断条件,还有我在编程过程中没有注意到day的输入必须大于0,导致我在最终的测试中一直出现逻辑错误从而无法通过一个测试点。

      在编写getNextDate()方法时,需要注意一些特殊的月份和号。比如在12月份时,需要注意输入的day是否为31,如果是31,则求下一天时需要对year+1,month重新赋值为1;在2月份时,需要注意输入的year是闰年或平年,输入的day是28或29;总之,在day与mon_maxnum[month]的值相等时,需要仔细分析和设计。

      设计完Date类后,在主方法中对其进行引用,首先需要判断输入的年月日是否符合要求,如果符合要求,才能进行getNeatDate()方法的引用,再输出Date;若不符合要求,则直接输出” Date Format is Wrong”后终止程序。

       在SourceMonitor的生成报表内容显示平均复杂度(Average Complexity)为2.69

 

      通过SourceMonitor分析,程序的平均方法没有位于绿色区域,说明方法编写出现了一点问题,需要改进。

 

题目3的7-4:

      这题需要设计一个类名为DateUtil,这道题是上一题的加强版,延用了上一题的checkInputValidity()方法和isLeapYear()方法;属性与上一题相同year,month,day,不同的是这一题的getNextDay()方法更为复杂,不仅要考虑单个方法,还需要考虑多个方法之间的调用,使用PowerDesigner后形成代码的类图,包含main类和DateUtil类

      首先是对DateUtil类的定义,这里对各种属性的定义与上一题相同,私有类型year、month、day和共有类型mon_maxnum来存放不同月份的天数。设计完year、month、day的getter和setter方法后,设计本题的难点—getNextNDay()方法。根据主方法中可以知道,getNeatNDay()方法的返回值类型为DateUtil,传入的参数是main方法中传入的天数n。首先调用isLeapYear()方法来判断year是闰年或平年,然后对n减去相应的一年中的天数。在循环中判断n是否大于year的天数(365或者366),若成立则继续执行上述操作,不断减小n的值,直到n小于year的天数(365或者366),每当n减去year的天数,则同时将year+1。当循环结束时,n已经小于当前year的天数,接下来就是将n剩余的天数落实到month和day上。核心语句是使用循环语句,只要n>mon_maxnum[month],即n大于当前月份的总天数,就将n减去该月的总天数,再将month加上一。需要注意的是到month为12时,需要额外设计if语句,使month为1,year加上一,不然月份就会为十三,这样会使mon_maxnum数组越界。在n脱离循环后,已经小于当前月份的总天数,接下来要做的就是将剩余的天数落实到day上。这一步比较简单,只需将n加到day上,需要注意的是,day加上n不得大于该月的总天数,不然会引起逻辑错误。当day加上n大于mon_maxnum[month]时,则要在month不等于12的情况下将month加一,在将day重新赋值为1后加上最后的n所剩的天数,如果此时month为12,需要设置新的if-else语句来分类讨论,不但月份要为一,年份也要加上一,day在重新赋值为1后加上n剩余的天数,这样即可求出后n天的天数。总体思路就是将n的天数不断减少,转换到初始日期上,使初始日期的值不断增大直至n为0,这样求得的日期就是后n天的日期。

       编写getPreviousNDays()方法的总体思路与getNextNDay()方法的总体思路相同,将n不断减小,将初始日期不断减小。在代码的编程过程中,只需对getNextNDay()方法进行需改即可,比如将传入的n先进行乘以-1的操作,然后在一些判断条件中将n改为-n,将部分循环条件的‘>‘与’<’互换,即可将原始日期向前倒退,需要注意的月份和天数不是12和mon_maxnum[month],而是1月份和1号,基本的原理都相等,进行部分需改即可得到getPreviousNDays()方法。

       在编写getDaysofDates()方法之前先要编写compareDates()方法和 equalTwoDates(),这两个方法是协助getDaysofDates()方法来完成功能3求天数差的。compareDates()用来比较传入的两个日期的大小,利用String的相关函数很容易实现;equalTwoDates()用来比较传入的日期是否相等,用Sting中的euqal方法即可实现。完成这两个方法后即可编写getDaysofDates。首先比较两个日期的大小,使用if-else语句,将小日期放在前面,大日期放在后面,保证结果不会为赋值。随后设置变量difference并赋值为0用来表示两者之间的天数差。主要思想是不断的增大小日期来靠近大日期,直至两个日期相等。用difference来记录小日期增大的天数,即可得到两个日期之间的差值,需要注意的是当月份为十二或天数为当前月份的天数最大值时。

       在完成DateUtil的类的设计后,在主方法中先设计变量来确定使用的功能,再调用相关的方法。如果输入1则调用getNextNDays()方法;如果输入2则调用getPreviousNDas()方法;如果输入3则调用getDaysofDates()方法。这样就完成题目的需求,三个不同的功能。

在SourceMonitor的生成报表内容显示平均复杂度(Average Complexity)为5.71。

        getNextNdays()方法编写的复杂度为22,是所有方法中最高的。原因可能是在减少n的值的过程中使用了太多的if-else语句,不断对年份、月份进行判断,造成复杂度过高,需要得到进一步的改进。

3. 踩坑心得:

        编写程序前一定要仔细阅读题目的要求和输出格式的限制,不能盲目的编写程序,不然就会在无数次错误中怀疑自己……

       这是第一次题目集的第一题,我一共提交了25次,原因就是没有按照题目的要求格式输出,期间还在不断的修改,以为自己的编程语句出现其他问题,所以编写程序前要仔细阅读题目题干,严格按照题目的输出格式输出

      还有就是需要注意当遇到题目浮点数的输出格式是到底是float型还是double型。

       这是第二次习题集的第一题,明明感觉编程过程很简单,但就是无法通过测试点,原因竟是题目隐形的限制了浮点数的输出格式为float

        两端代码的唯一区别就是浮点数的输出格式,前者为double,后者float,这样的错误在第三题也是只能输出float型而不能输出double型,不然会无法通过测试点,属于是两次掉在同一个坑里了。

然而诡异的是第三次习题集的第二题只能输出double型而不能是float

        前五次的错误仅仅只是因为输出的格式是float型而不是double型修改前为

         将变量修改为double型后

        就能够通过所以的测试点,所以说float型和double型真的是非常诡异,在题目没有明确说明使用哪种形式时,只能谨慎选择了。

还有就是注意题目的条件要求,要仔细分析。比如第三次题目集的第三题

    在编程时一直有一个测试点无法通过,最终通过仔细检查发现时为符合题目条件当输入为负数时程序依旧运行

 

    在修改后符合题目条件后

就能过通过所有测试点了。

       最后就是编写程序一定要严谨,一定要覆盖到所有可能出现的情况,一定要仔细分析,然后覆盖到所有的情况。比如第三次题目集的第四题,我始终没有考虑到使用year+1作为不断循环的条件,导致部分测试点无法通过

所以写程序的时候一定要考虑到所有的情况,以防错误……

4. 改进建议:

     我的第三次题目集的第四题的编程太过复杂,平均复杂度为5.71,不符合区间良好代码区间的[2,4],所以需要改进一下,优化一下对年份、月份、日期的判断过程,比如我在判断是否为闰年时进行了多次的重复判断,从而造成复杂度的提高

我应该将重复判断的过程删去,避免重复判断,降低效率;应该将判断语句置于每次循环开始时。

还有就是该代码存在一定的逻辑错误,虽然代码能够通过PTA的所有测试点

但实际上存在逻辑错误,当输入1 1999 3 28 6543时本该输出1999-3-28 next 6543 days is:2017-2-24,但实际上它的输出结果却是

输出结果比实际结果多一天。只需要修改条件将isLaepYear(year)改为isLeapYear(year+1)就能解决这个逻辑错误

5. 总结:

       通过这三次题目集,我在不断学习、完成题目、查找资料的过程中,完成了从对Java一窍不通到掌握基本的语法转变。第一次题目集让我第一次使用Java这门编程语言,刚开始还无法从C语言的面向过程的编程走出来,比如main(String[] args)方法中的括号总是忘记输入String[] args而导致错误;总是想要使用scanf来完成输入……在完成第一次题目集后,我初步掌握了Java的基本编程知识。在第二次的题目集中,加强了我对选择结构和字符串中的知识点的掌握。Java字符串有很多便利的方法,比如String.charAt、String.substring、String.indexOF……等方法,通过第二次题目集,我感受到Java中需要掌握的方法比C语言中多的多。在第三次的题目集中,我学会了如何去定义一个类、定义构造方法以及对类中属性使用private来实现封装,初步感受到为什么说C是面对过程而Java是面对对象。