(1)前言

pta第四次作业的7-2到7-4主要学会了运用容器类——LinkedHashSet,对重复的数据进行检查,刚入手有点不熟练。7-7通过查询Java API文档,了解了Scanner类中nextLine()等方法、String类中split()等方法、Integer类中parseInt()等方法的用法,了解LocalDate类中of()、isAfter()、isBefore()、until()等方法的使用规则,了解ChronoUnit类中DAYS、WEEKS、MONTHS等单位的用法。难度中等。

pta第五次作业中前四题主要是学习了如何使用正则表达式,后两题主要学习了类与类之间的关系中的聚合,上手不太熟练,难度较高。

pta第六次作业中是菜单类的迭代,个人认为难度极高,以至于最后没有完成。

 

(2)设计与分析(对题目源码分析,参考power。。有相应的解释和心得)

————训练题集04中题目难度不高,主要是对是否有重复的数据的判断,以及如何去掉重复的数据。

首先7-2中判断是否有重复的数据,我一开始使用的是多重循环,逐个比较是否有数据重复,出现重复,则判断成功,程序终止。如下图所示

 

但是发现这样的坏处就是,当出现重复的数据存在在数组中的下标很大时,则耗时很长,所以导致了超时 如下图所示(很慢,很慢)。

 

 所以当时翻阅资料,发现可以运用下面的LinkedHashSet表,

  • LinkedHashSet中的元素没有重复
  • LinkedHashSet中的元素有顺序,维护了添加顺序
  • LInkedHashSet可以存储null值
  • LinkedHashSet是一个线程不安全的容器

所以这道题我使用了哈希表,先创建他的一个对象。

 

 然后利用一层循环往表里赋值,并在循环的过程中,利用i值与表当时大小进行比较,如果不相等,则说明出现了重复的数据,如下图。

 

于是这道题很快就能被解答出来。

7-3中需要去除重复的数据,并且输出。这道题的整体思路与上一题一样,同样避免超时,以及保证高效性,运用了hash表。

同样先创建hashset的对象,因为需要输出,所以先用数组存储输入数据,后利用循环,将每次输入的数据填入hashset中,如下图。

 

但是,题目中还要求在最后一个输出结束后不能有空格,则需要进行判断输出的数是否为最后一个,所以运用了for-each循环,并且需加入一个计数器int变量number,当number==此表的size时,说明已经是最后一个输出,则不输出空格。如下图所示。

 

 

 7-4中题目要求去除字符串中指定的字符,所以立刻想到了运用String类中的split方法,可以有效的将指定字符去除,并且得到一个字符数组。题目中还提到了重复单词只能出现一次,所以果断运用前面学到的hash表,对split处理后的字符数组用for循环进行存储如下图。

由于需要对处理后的数组按照题目要求进行输出,运用ArrayList将set表中的数据存储在list中,并用for循环将list中的数据存储到字符串数组中,这样方便对每个字符串进行比较和排序输出如下图。

ArrayList试剂盒的一种,比数组好的方面有:

  • 集合的大小不固定,可以动态变化
  • 集合提供很多方便好用的功能
  • 集合的类型不固定

就是要注意需要import一个java.util.ArrayList;

 

 

中间的比较过程略微复杂,需要先比较长度,长度一致的情况下,在比较每个字符的大小,最后比较轻易的解出答案。

 

————训练题集05中前四题为正则表达式的训练,难度较低。主要为后两题 类的聚合 日期类的编写。

7-5中类的设计如下

 

 首先,现将年份Year类编写好,让年份属性为私有类,接着编写月份Month类,日Day类,最后用DateUtil类进行处理。此题为前面日期类题的迭代,主要是对聚合这一关系进行理解,并且了解其中通过方法来访问私有化变量。

根据题目中给的类图设计各个类,其中由于各个类中的属性都是私有的,并且在聚合的过程中,包括类都是私有的属性,所以每个类都需要创建对应各个属性的getter和setter的方法,如下图所示(例子):

 通过一系列操作可以体现出封装性。

 

 

 

7-6的题目将年份,月份以及天数类聚合在大类Dateutil里,依旧是对类的设计以及通过方法来访问私有化变量,并且通过方法进行赋值。

首先先将年、月、日三个类编写好,随后编写DateUtil类,并且将年月日的getter和setter方法都编写在DateUtil下。

题目大致要求如下:

  1. 求下n天
  2. 求前n天
  3. 求两个日期相差的天数

其中判断两个日期的日期差的方法编写比较困难:

我先定义一个变量n,为0,表示这两个日期相差天数,然后判断两个日期是否为闰年(闰年则要让二月份的天数变成29天,否则会出错)代码如下:

public int getDaysofDates(DateUtil date)
{
int n=0;
if(this.year.isLeapYeaar())
this.mon_maxnum[2]=29;
else this.mon_maxnum[2]=28;
if(date.year.isLeapYeaar())
date.mon_maxnum[2]=29;
else date.mon_maxnum[2]=28;
if(equalTwoDates(date)){
return n;
}

随后在比较两个日期的先后(其中要用到比较日期大小的方法,如果比参数日期大,则返回true,否则false):

  public boolean compareDates(DateUtil date)//比较大小的方法
  {
  if(this.getDay().getMonth().getYear().getValue()>date.getDay().getMonth().getYear().getValue()) return true;
  if(this.getDay().getMonth().getYear().getValue()==date.getDay().getMonth().getYear().getValue()){
  if(this.getDay().getMonth().getValue()>date.getDay().getMonth().getValue()){
  return true;
  }else if(this.getDay().getMonth().getValue()==date.getDay().getMonth().getValue()){
  if(this.getDay().getValue()>date.getDay().getValue()){
  return true;
  }else return false;
  }else return false;
  }else return false;
  }   

 public boolean equalTwoDates(DateUtil date)//比较相同的方法

    {
 if(this.getDay().getMonth().getYear().getValue()==date.getDay().getMonth().getYear().getValue()&&this.getDay().getMonth().getValue()==date.getDay().getMonth().getValue()&&this.getDay().getValue()==date.getDay().getValue()) return true;
else return false;
}

如果两个日期相同,则直接返回n的值(此时n=0)。(先看可不可以相同)如下图:

    if(equalTwoDates(date)){
    return n;
    }

如果此日期比参数日期要大,我先将此日期的年数减去参数日期的年数,由于相差的年份间可能会出现闰年,所以不能直接将相差的年份*365,而是选择用for循环,进行累加(这样可以再循环中判断闰年,如果闰年,n+366,不是闰年,n+365)具体代码如下图:

  for(int i=0;i<this.year.getValue()-date.year.getValue();i++){
  if(date.year.isLeapYeaar(i)){
  n+=366;
  }else n+=365;
  }

如果此日期比参数日期要小,则用参数日期的年数减去此日期的年数,再按照上述处理。

求下n天的时候,我先编写一个求下一天的方法:(其中也需要判断闰年)先判断是否为12月,后判断是否是最后一天,中间使用较多if-else语句,注意格式,还是不容易出错的。如下图:

 然后利用一个for循环,循环内每次执行的内容便是求下一天的方法,最后求出下n天,如下图:

 

在求前n天的方法与求下n天的方法类似,先编写求前1天的方法。要注意判断闰年的时候修改2月份的天数,以及当是1月1日时,年份减1,并且日期为12月31日

 

————训练题集06中7-1是一个菜单程序的设计我认为难度较大,以至于最后没有通过大部分的测试点,也没有将程序最后给编写完成,但过程中还是将大部分类的编写给完成

目前编写完的类图如下:

 

首先对菜品类进行编写,其中包括名字和单价如下图:

然后编写一个方法,获得一个返回各个分量单价的值,利用if语句进行控制,如下图

 --菜谱类

首先,用ArrayList容器对各个菜品进行存放(一开始想用数组,但发现如果出现修改或删除菜谱类的菜单的情况,果断换个容器)。

然后编写一个返回Dish对象的方法,方法中,利用for-each循环,遍历整个菜谱,如果找到名字相同的菜,则返回那个菜品类,如下图。

 

再编写一个增加菜品的方法,并返回那个菜品类,同样适用for-each循环找出相同名字的菜品,如下图:

接着设计一个点菜记录类,将菜品记录保存下来:

设计一个Order类,将订单的所有点的菜的信息保存下来,其中需要利用ArrayList来存储record类,利用for循环将点的菜品的总价计算出来如下图:

 接着编写一个方法,增加一条订单的信心如下:

 方法中使用到menu中的searchDish方法,用来查找是否存在此名字的菜品,如果dish为空,则返回null,并且输出文字,如下图:

 如果有此菜品,则new一个record对象,并将该对象存放在records的容器类中,最后输出该菜品的信息,并返回record。

 

 

 

(3)采坑心得

————训练集04中容易将开头表明类的时候,将.打成,导致编译错误,虽然事很小 但还是需要引起重视。

————训练题集04中使用了String类中的split方法,一开始以为方法返回的是String类的值,导致一直报错,后面查询了该方法的使用,发现是将分割开来的各个字符串,放在数组中,并且返回一个字符数组,所以需要用String数组来存放,代码如下:

String string=in.nextLine();
String[] split=string.split(",|\\.| ");

以及对数组和String的长度,以及LinkedHashSet和ArrayList的长度的表达容易出错如下图(正确结果)

总结一下长度的表示:

LinkedHashSet的对象的长度用.size()来表示。

ArrayList的对象的长度用.size()来表示。

数组的对象的长度用.length来表示。

String的对象的长度用.length()来表示。

 

————训练题集05中7-5没有注意类的初始化都是私有的,所以在访问值的时候,一直会直接用 类.变量名来访问,然后就会导致编译错误,解决方案是,利用get方法返回变量值来访问私有属性。如下图所示

 

 (4)改进建议

1.首先在训练题集5中的日期类设计,题目中给的月份天数的数组是如下图所示的:

 但是当我使用到这个数组的时候发现,1月份的天数对应的数组中0下标代表的数字,2月份的天数对应的是数组中1下标的数字,使用起来不方便,所以将该数组改进为下列数组,下标0的时候天数为零,以后不变 如下图:

 

 

 

(5)总结

 这三次作业是老师布置的第二次作业,也是我入门java的第二次作业,题目总体来说难度偏难,在算法方面自身能力比较薄弱,并且对各个类的各种方法大部分不太了解并不会使用,还是不能不能达到速成代码的境界,但较难的题目也能被自己软磨硬泡弄出来。自身的java语法得到了提高,对类和方法的设计也有了进一步的认知和理解,对题目中出现的类和各个方法又熟悉了许多,拓展了自己关于各个类的方法的视野,但自身java语法基础仍然比较薄弱,例如String的方法有些仍然不能灵活运用,以及对类与对象的理解仍然不足,下一步,首先继续保持java的系统不断点的线上学习,多上机实验,将知识转化到程序代码上,并将更多时间花在类的构造上,已经Java库中拥有的类及其方法多去探索和使用。

对课程和老师的建议:希望在pta上布置一些中等难度的题目,尽量涉及到新学的内容,方便记忆,同时希望课堂上讲的知识能够运用到实例上展示出来。虽然很希望自己能上手多操作,但是很多东西操作的时候都不是很会,希望老师能够在课堂上讲知识的时候,讲完时候能跟上一个比较通俗易懂的实例案件和代码,然后再给同学们出道类似的题目去完成,这样方便学生在上手的同时,能够有思路,并且能够熟悉所讲的知识。