一、前言
本次博客是主要针对在java学习第二阶段中的PTA作业的总结性博客,第二阶段的作业的难度与第一次阶段相比有所提高,对java的知识点的考察主要集中在正则表达式的运用、类的继承、多态,以及数据结构中的一系列知识。
二、题目分析
1、期中考试题
这次考试我是在最后几分钟内才做完了题目,说实话,我最大的缺点就是没有认真审题,导致我浪费了许多时间,继而导致我最后的代码有很多瑕疵。在display类中我应该在第二题中就改为所有的输出,而我还在主函数里输出,导致虽然测试结果与答案一致,但是一直只有16分,直到我在做最后一题时才幡然醒悟,将display类给改正。所有我下次做题一定要认真仔细审题。还有我在第三题上还有许多瑕疵,我在考后对Main方法进行了一些修改,代码如下:
public class Main { public static void main(String[] args) { Scanner in=new Scanner(System.in); GeometryObject geometryObject =new GeometryObject(); int choice = in.nextInt(); while(choice != 0) { switch(choice) { case 1: double x1=in.nextDouble(); double y1=in.nextDouble(); Point point=new Point(x1,y1); geometryObject.add(point); break; case 2: double x2=in.nextDouble(); double y2=in.nextDouble(); double x3=in.nextDouble(); double y3=in.nextDouble(); String color1=in.next(); Point point1=new Point(x2,y2); Point point2=new Point(x3,y3); Line line=new Line(point1,point2,color1); geometryObject.add(line); break; case 3: String color2=in.next(); Plane plane=new Plane(color2); geometryObject.add(plane); break; case 4: int index = in.nextInt(); if(index-1>=0&&index<=geometryObject.getList().size()) geometryObject.remove(index-1); } choice = in.nextInt(); } for (Element element: geometryObject.getList()) { element.display(); } } }
我修改了2个点
一是把全局变量改为了局部变量,段老师曾提醒我们最好不要使用全局变量,考试的时候我为了节省时间没有注意这一点;
二是将for循环改为了foreach,我觉得对于学过的东西,最好的方式就是去熟练运用它,可考试的时候我浑然忘记了它,很是可惜。
2、pta06第二题 点线形系列4-凸四边形的计算
这题我没有拿满分,我承认是我的能力不足,在情况4的时候我卡住了,然后就没有接着往下写了。说实话,这题目的检查点是真的恶心,在没有把当前情况的检查点过去时,对于我这个强迫症患者来说,比杀了我还要难受,所以,每一个情况我都花了大量的时间去调试,每一个稍微复杂一点的方法我都至少写过两遍以上,现在去看的时候已经记不得我当时的代码思路了,我写的方法也不知道是哪一个,因为我的方法名字是a,b,c之类的,好吧,我下次写代码的时候一定要多注意这个点。
在最开始判断是否为四边形的时候,我就在草稿纸上疯狂输出,最后在一大堆的代码下才成功判断是否为四边形,可是接下来的每一种情况都是在四边形为基础上进行的,所以我又重新将其写为一个判断四边形的方法。所以啊,下次在写代码的时候一定要先构思它的结构,这样的写代码才更加快捷,高效。还有的就是,写这种题目一定要在草稿纸上先进行一些演算,不然是根本写不下去的。
在输出面积的时候我用的是海伦公式推算出来的面积,结果总是有误差,pta的检查点它不认这个结构,真是烦人。还有判断四点两两相交的时候,我竟然发现java的算法里它有自带的这种功能,java真是强大!以下是我只有前三个情况判断方法的代码,每个检查点在我的死命排查下都过了,可喜可贺。
public static boolean b(Double x1, Double y1, Double x2, Double y2, Double x3, Double y3) { double k1, k2, k3, k4, k5, k6; k1 = y1 - y2; k2 = x1 - x2; k3 = k1 / k2; k4 = y3 - y1; k5 = x3 - x1; k6 = k4 / k5; if (k2 == 0) { if (x1 == x3) return true; else return false; } else if (k3 == k6) return true; else return false; } public static boolean c(Double x1, Double y1, Double x2, Double y2, Double x3, Double y3, Double x4, Double y4) { if (((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) * ((x1 - x2) * (y1 - y4) - (y1 - y2) * (x1 - x4)) < 0 && ((x3 - x4) * (y3 - y1) - (y3 - y4) * (x3 - x1)) * ((x3 - x4) * (y3 - y2) - (y3 - y4) * (y3 - y2)) < 0) { return true; } else return false; // double a = - (y2 - y1) / (x2 - x1); // double b = 1.0, d = 1.0; // double c = - (y4 - y3) / (x4 -x3); // if (a * d - b * c != 0){ // return true; // } // return false; } public static boolean isQuadrilateral(Double x1, Double y1, Double x2, Double y2, Double x3, Double y3, Double x4, Double y4) { if (!b(x1, y1, x2, y2, x3, y3) && !b(x1, y1, x2, y2, x4, y4) && !b(x1, y1, x3, y3, x4, y4) && !b(x2, y2, x3, y3, x4, y4)) { if (!have(x1, y1, x2, y2, x3, y3, x4, y4) && !have(x1, y1, x4, y4, x2, y2, x3, y3)) { return true; } else return false; } else return false; } private static boolean have(Double x1, Double y1, Double x2, Double y2, Double x3, Double y3, Double x4, Double y4) { Line2D line1 = new Line2D.Double(x1, y1, x2, y2); Line2D line2 = new Line2D.Double(x3, y3, x4, y4); if (line2.intersectsLine(line1)) { return true; } else return false; } public static boolean isParallelogram(Double x1, Double y1, Double x2, Double y2, Double x3, Double y3, Double x4, Double y4) { double a1, a2, a3, a4; a1 = Math.sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2))); a2 = Math.sqrt(((x2 - x3) * (x2 - x3)) + ((y2 - y3) * (y2 - y3))); a3 = Math.sqrt(((x3 - x4) * (x3 - x4)) + ((y3 - y4) * (y3 - y4))); a4 = Math.sqrt(((x1 - x4) * (x1 - x4)) + ((y1 - y4) * (y1 - y4))); if (a1 == a3 && a2 == a4) return true; else return false; } public static boolean isLozenge(Double x1, Double y1, Double x2, Double y2, Double x3, Double y3, Double x4, Double y4) { double a1, a2, a3, a4; a1 = Math.sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2))); a2 = Math.sqrt(((x2 - x3) * (x2 - x3)) + ((y2 - y3) * (y2 - y3))); a3 = Math.sqrt(((x3 - x4) * (x3 - x4)) + ((y3 - y4) * (y3 - y4))); a4 = Math.sqrt(((x1 - x4) * (x1 - x4)) + ((y1 - y4) * (y1 - y4))); if (a1 == a2 && a2 == a3 && a3 == a4) return true; else return false; } public static boolean isRectangle(Double x1, Double y1, Double x2, Double y2, Double x3, Double y3, Double x4, Double y4) { double a1, a2, a3, a4, a5; a1 = x1 - x2; a2 = y1 - y2; a3 = x3 - x2; a4 = y3 - y2; a5 = a1 * a3 + a2 * a4; return a5 == 0; } public static boolean isConvex(Double x1, Double y1, Double x2, Double y2, Double x3, Double y3, Double x4, Double y4){ double result1 = Math.abs((x1 * y2 + x2 * y4 + x4 * y1 - x2 * y1 - x4 * y2- x1 * y4) / 2.0); double result2 = Math.abs((x1 * y2 + x2 * y3 + x3 * y1 - x2 * y1 - x3 * y2- x1 * y3) / 2.0); double result3 = Math.abs((x1 * y4 + x4 * y3 + x3 * y1 - x4 * y1 - x3 * y4- x1 * y3) / 2.0); double result4 = Math.abs((x2 * y4 + x4 * y3 + x3 * y2 - x4 * y2 - x3 * y4- x2 * y3) / 2.0); double a1=result1+result4; double a2=result2+result3; if(a1==a2) return true; else return false; } public static String put(double num) { String str_S = String.valueOf(num); str_S = str_S.substring(str_S.indexOf(".") + 1); int len_S = str_S.length(); len_S = Math.min(len_S, 3); String out2 = String.format("%."+len_S+"f", num); return out2; }
3、链表作业
对于链表这个东西,我是深恶痛绝的。我上学期的链表没学好,还好期末考试没考多少,结果这学期我的c语言课设是链表操作演示,我是真的想笑。我跟链表这个东西是真的有缘粪啊。没办法,我先是在CSDN上找了一些关于这个java实现链表的东西,学了一会就搞定了,照葫芦画瓢的东西。还有双向链表也一样,就是又创建一个指向头结点的类似指针的东西使整个代码成为一个循环。我认为有些要注意的点就是它的边界值问题,无论是单项和双向都是如此。这是类图:
三、学到的知识
最近我们学了数据结构的不少东西,分别如下:
1、set
注重独一无二的性质,该体系集合可以知道某物是否已近存在于集合中,不会存储重复的元素
用于存储无序(存入和取出的顺序不一定相同)元素,值不能重复。
对象的相等性
引用到堆上同一个对象的两个引用是相等的。如果对两个引用调用hashCode方法,会得到相同的结果,如果对象所属的类没有覆盖Object的hashCode方法的话,hashCode会返回每个对象特有的序号(java是依据对象的内存地址计算出的此序号),所以两个不同的对象的hashCode值是不可能相等的。
如果想要让两个不同的Person对象视为相等的,就必须覆盖Object继下来的hashCode方法和equals方法,因为Object hashCode方法返回的是该对象的内存地址,所以必须重写hashCode方法,才能保证两个不同的对象具有相同的hashCode,同时也需要两个不同对象比较equals方法会返回true
该集合中没有特有的方法,直接继承自Collection。
2、hashset
HashSet实现Set接口,底层由HashMap(后面讲解)来实现,为哈希表结构,新增元素相当于HashMap的key,value默认为一个固定的Object。在我看来,HashSet相当于一个阉割版的HashMap;
当有元素插入的时候,会计算元素的hashCode值,将元素插入到哈希表对应的位置中来;
具有如下特点:
不允许出现重复因素;
允许插入Null值;
元素无序(添加顺序和遍历顺序不一致);
线程不安全,若2个线程同时操作HashSet,必须通过代码实现同步;
3、treeset
从名字上可以看出,此集合的实现和树结构有关。与HashSet集合类似,TreeSet也是基于Map来实现,具体实现TreeMap(后面讲解),其底层结构为红黑树(特殊的二叉查找树);
与HashSet不同的是,TreeSet具有排序功能,分为自然排序(123456)和自定义排序两类,默认是自然排序;在程序中,我们可以按照任意顺序将元素插入到集合中,等到遍历时TreeSet会按照一定顺序输出--倒序或者升序;
具有如下特点:
对插入的元素进行排序,是一个有序的集合(主要与HashSet的区别);
底层使用红黑树结构,而不是哈希表结构;
允许插入Null值;
不允许插入重复元素;
线程不安全;
4、stream
Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
特点:
1、不是数据结构,不会保存数据。
2、不会修改原来的数据源,它会将操作后的数据保存到另外一个对象中。(保留意见:毕竟peek方法可以修改流中元素)
3、惰性求值,流在中间处理过程中,只是对操作进行了记录,并不会立即执行,需要等到执行终止操作的时候才会进行实际的计算。
它有不少功能
sorted 排序操作,对元素排序。
skip 跳过操作,跳过某些元素。
map 将每一个元素进行操作,然后转给下一个
limit 取前n个
distinct 去重
filter 过滤
findany 选择该流中的任何元素。
anyMatch判断的条件里,任意一个元素成功,返回true
allMatch判断条件里的元素,所有的都是,返回true
noneMatch 与allMatch相反,判断条件里的元素,所有的都不是,返回true
5、Lambda
使用 Lambda 表达式原因
Lambda 是一个匿名函数,可以把 Lambda表达式 理解为是一段可以传递的代码 (将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升
Lambda 表达式的基础语法 : Java8 中引入了一个新的操作符 "->" 该操作符称为箭头操作符或 Lambda 操作符,箭头操作符将 Lambda 表达式拆分成两部分 :
左侧 : Lambda 表达式的参数列表
右侧 : Lambda 表达式中所需执行的功能, 即 Lambda 体。
四、学习总结
1、在写题目的时候一定要审题清楚,正如段老师所言,题目给的东西就是甲方,我们的目的就是去完成它,不要考虑其他的事情;
2、面向对象编程不能注重于按步骤一步一步解决问题,而应该注重于将问题中的部分分成各个对象,各司其职,谁做了什么事,谁又做了什么事,他们共同作用的结果解决了一件事;
3、对于新学习的东西一定要多看多练,这样才能更快速高效的掌握;
4、编程过程中的每一个步骤都要仔细思考,确保该步骤的有效性以及高效性,对于一些复杂的算法更要注重每一个步骤的逻辑严谨性,一招不慎满盘皆输,只用所有的步骤都是正确的,逻辑都是严谨正确的才能得出最后的正确答案。教训:在完成作业的过程中,往往因为某一个步骤的错误,程序能够正常运行却不能够得出正确的答案。
编程之路漫漫,我将不断求索!