前言:
这三周的Java课程主要学习了Collections接口的很多实现。了解了一些基本数据类型并可以做一些简单的运用。在这三周的题目量并不多,但是题目难度有所提升。PTA中的题目集很难像以前那样拿到满分。并且每次都会对题目进行迭代,无形中迫使我们需要认真设计类,才能完成后续迭代的需求,加强了对OOP的运用和理解。
设计与分析:
PTA图形类设计:
题目描述:
类图:没有进行类的设计。
源码:
1 import java.util.Scanner; 2 3 public class Main { 4 public static void main(String[] args) { 5 Scanner in = new Scanner(System.in); 6 String line = in.nextLine(); 7 try { 8 int coi = Integer.parseInt(line.substring(0, 1)); 9 if (coi < 1 || coi > 5) { 10 System.out.print("Wrong Format"); 11 System.exit(0); 12 } 13 switch (coi) { 14 case 1: 15 System.out.print(calculateSlope(line.substring(2))); 16 break; 17 case 2: 18 System.out.print(calculateDistance(line.substring(2))); 19 break; 20 case 3: 21 System.out.print(isColinear(line.substring(2))); 22 break; 23 case 4: 24 System.out.print(isParallel(line.substring(2))); 25 break; 26 case 5: 27 System.out.print(isIntersectWithinSegment(line.substring(2))); 28 break; 29 } 30 } catch (Exception e) { 31 System.out.print("Wrong Format"); 32 System.exit(0); 33 } 34 } 35 36 /** 37 * 计算两点构成线段的斜率 38 */ 39 public static double calculateSlope(String data) { 40 String[] points = data.split(" "); 41 42 String point1 = points[0], point2 = points[1]; 43 double x1 = 0, y1 = 0; 44 double[] xy = processData(point1); 45 x1 = xy[0]; 46 y1 = xy[1]; 47 48 double x2 = 0, y2 = 0; 49 xy = processData(point2); 50 x2 = xy[0]; 51 y2 = xy[1]; 52 if (points.length != 2) { 53 System.out.print("wrong number of points"); 54 System.exit(0); 55 } 56 if (Math.abs(x1 - x2) < 1e-6 && Math.abs(y1 - y2) < 1e-6) { 57 System.out.print("points coincide"); 58 System.exit(0); 59 } 60 if (Math.abs(x1 - x2) < 1e-6) { 61 System.out.print("Slope does not exist"); 62 System.exit(0); 63 } 64 65 return (y1 - y2) / (x1 - x2); 66 } 67 68 /** 69 * 判断三点是否在一条直线上 70 */ 71 public static boolean isColinear(String data) { 72 String[] points = data.split(" "); 73 74 String point3 = points[2]; 75 String point1 = points[0]; 76 String point2 = points[1]; 77 double x1 = 0, y1 = 0; 78 double[] xy = processData(point1); 79 x1 = xy[0]; 80 y1 = xy[1]; 81 82 double x2 = 0, y2 = 0; 83 xy = processData(point2); 84 x2 = xy[0]; 85 y2 = xy[1]; 86 87 double x3 = 0, y3 = 0; 88 xy = processData(point3); 89 x3 = xy[0]; 90 y3 = xy[1]; 91 92 if (points.length != 3) { 93 System.out.print("wrong number of points"); 94 System.exit(0); 95 } 96 97 if (Math.abs(x2 - x3) < 1e-6 && Math.abs(y2 - y3) < 1e-6) { 98 System.out.print("points coincide"); 99 System.exit(0); 100 } else if (Math.abs(x1 - x3) < 1e-6 && Math.abs(y1 - y3) < 1e-6) { 101 System.out.print("points coincide"); 102 System.exit(0); 103 } else if (Math.abs(x1 - x2) < 1e-6 && Math.abs(y1 - y2) < 1e-6) { 104 System.out.print("points coincide"); 105 System.exit(0); 106 } 107 108 if (Math.abs(x1 - x2) > 1e-6) { 109 double k = calculateSlope(points[0] + " " + points[1]); 110 double b = y1 - k * x1; 111 return Math.abs(k * x3 + b - y3) < 1e-6; 112 } else { 113 return Math.abs(x1 - x3) < 1e-6; 114 } 115 116 } 117 118 /** 119 * 判断是否平行 120 */ 121 public static boolean isParallel(String data) { 122 String[] points = data.split(" "); 123 String point1 = points[0], point2 = points[1], point3 = points[2], point4 = points[3]; 124 125 double x1 = 0, y1 = 0; 126 double[] xy = processData(point1); 127 x1 = xy[0]; 128 y1 = xy[1]; 129 130 double x2 = 0, y2 = 0; 131 xy = processData(point2); 132 x2 = xy[0]; 133 y2 = xy[1]; 134 135 double x3 = 0, y3 = 0; 136 xy = processData(point3); 137 x3 = xy[0]; 138 y3 = xy[1]; 139 140 double x4 = 0, y4 = 0; 141 xy = processData(point4); 142 x4 = xy[0]; 143 y4 = xy[1]; 144 if (points.length != 4) { 145 System.out.print("wrong number of points"); 146 System.exit(0); 147 } 148 if (Math.abs(x1 - x2) < 1e-6 && Math.abs(y1 - y2) < 1e-6 149 || Math.abs(x3 - x4) < 1e-6 && Math.abs(y3 - y4) < 1e-6) { 150 System.out.print("points coincide"); 151 System.exit(0); 152 } 153 154 if (Math.abs(x1 - x2) > 1e-6 && Math.abs(x3 - x4) > 1e-6) { 155 double k1 = calculateSlope(point1 + " " + point2); 156 double k2 = calculateSlope(point3 + " " + point4); 157 return Math.abs(k1 - k2) < 1e-6; 158 } else return Math.abs(x1 - x2) < 1e-6 && Math.abs(x3 - x4) < 1e-6; 159 } 160 161 /** 162 * 判断交点位置 163 */ 164 public static boolean isIntersectWithinSegment(String data) { 165 String[] points = data.split(" "); 166 String point1 = points[0], point2 = points[1], point3 = points[2], point4 = points[3]; 167 168 double x1 = 0, y1 = 0; 169 double[] xy = processData(point1); 170 x1 = xy[0]; 171 y1 = xy[1]; 172 173 double x2 = 0, y2 = 0; 174 xy = processData(point2); 175 x2 = xy[0]; 176 y2 = xy[1]; 177 178 double x3 = 0, y3 = 0; 179 xy = processData(point3); 180 x3 = xy[0]; 181 y3 = xy[1]; 182 183 double x4 = 0, y4 = 0; 184 xy = processData(point4); 185 x4 = xy[0]; 186 y4 = xy[1]; 187 188 if (points.length != 4) { 189 System.out.print("wrong number of points"); 190 System.exit(0); 191 } 192 if (Math.abs(x1 - x2) < 1e-6 && Math.abs(y1 - y2) < 1e-6 193 || Math.abs(x3 - x4) < 1e-6 && Math.abs(y3 - y4) < 1e-6) { 194 System.out.print("points coincide"); 195 System.exit(0); 196 } 197 if (Math.abs(x1 - x2) < 1e-6 && Math.abs(x3 - x4) < 1e-6) { 198 System.out.print("is parallel lines,have no intersection point"); 199 System.exit(0); 200 } 201 if ( Math.abs(x1 - x2) < 1e-6) { 202 double k = calculateSlope(point3 + " " + point4); 203 double b = y4 - k * x4; 204 double y = k * x1 + b; 205 System.out.print(x1 + " " + y + " "); 206 return (y < Math.max(y1, y2) && y > Math.min(y1, y2)) || (x1 < Math.max(x3, x4) && x1 < Math.min(x3, x4)); 207 } 208 if ( Math.abs(x3 - x4) < 1e-6) { 209 double k = calculateSlope(point1 + " " + point2); 210 double b = y1 - k * x1; 211 double y = k * x3 + b; 212 System.out.print(x3 + " " + y + " "); 213 return (y < Math.max(y3, y4) && y > Math.min(y3, y4)) || (x3 < Math.max(x1, x2) && x3 > Math.min(x2, x1)); 214 } 215 double k1 = calculateSlope(point1 + " " + point2), k2 = calculateSlope(point3 + " " + point4); 216 if ( Math.abs(k1 - k2) < 1e-6) { 217 System.out.print("is parallel lines,have no intersection point"); 218 System.exit(0); 219 } 220 double b1 = y1 - k1 * x1; 221 double b2 = y3 - k2 * x3; 222 double x = (-b1 + b2) / (k1 - k2); 223 double y = - (k1 * b2 - k2 * b1) / (k2 - k1); 224 System.out.print(x + " " + y + " "); 225 return (x < Math.max(x1, x2) && x > Math.min(x1, x2)) || (x < Math.max(x3,x4) && x > Math.min(x3, x4)); 226 } 227 228 /** 229 * 计算点到直线的距离 230 */ 231 public static double calculateDistance(String data) { 232 String[] points = data.split(" "); 233 234 String point3 = points[2]; 235 String point1 = points[0]; 236 String point2 = points[1]; 237 double x1 = 0, y1 = 0; 238 double[] xy = processData(point1); 239 x1 = xy[0]; 240 y1 = xy[1]; 241 242 double x2 = 0, y2 = 0; 243 xy = processData(point2); 244 x2 = xy[0]; 245 y2 = xy[1]; 246 247 double x3 = 0, y3 = 0; 248 xy = processData(point3); 249 x3 = xy[0]; 250 y3 = xy[1]; 251 if (points.length != 3) { 252 System.out.print("wrong number of points"); 253 System.exit(0); 254 } 255 if (Math.abs(x3 - x2) < 1e-6 && Math.abs(y3 - y2) < 1e-6) { 256 System.out.print("points coincide"); 257 System.exit(0); 258 } 259 260 if (Math.abs(x2 - x3) > 1e-6) { 261 double k = calculateSlope(points[1] + " " + points[2]); 262 double b = y1 - k * x1; 263 return Math.abs(k * x1 + b - y1) / Math.sqrt(k * k - 1); 264 } else { 265 return Math.abs(x1 - x2); 266 } 267 268 } 269 270 public static void check(String point, int pos) { 271 for (int loop = 0; loop < point.length(); loop++) { 272 if (point.charAt(loop) == '.') { 273 if (loop == 0 || loop == pos + 1) { 274 System.out.print("Wrong Format"); 275 System.exit(0); 276 } 277 } 278 if (point.charAt(loop) == '.') { 279 if (loop == pos - 1 || loop == point.length() - 1) { 280 System.out.print("Wrong Format"); 281 System.exit(0); 282 } 283 } 284 } 285 if (point.charAt(0) == '0' && point.charAt(1) != '.' && point.charAt(1) != ',') { 286 System.out.print("Wrong Format"); 287 System.exit(0); 288 } else if (point.length() > pos + 2) { 289 if (point.charAt(pos + 1) == '0' && point.charAt(pos + 2) != '.' && point.charAt(pos + 2) != ',') { 290 System.out.print("Wrong Format"); 291 System.exit(0); 292 } 293 } 294 } 295 296 public static double[] processData(String point) { 297 double x = 0, y = 0; 298 int pos = 0; 299 for (int loop = 0; loop < point.length(); loop++) { 300 if (point.charAt(loop) == ',') { 301 pos = loop; 302 } 303 } 304 check(point, pos); 305 x = Double.parseDouble(point.substring(0, pos)); 306 y = Double.parseDouble(point.substring(pos + 1)); 307 return new double[]{x, y}; 308 } 309 }
分析:为了追求解题速度,没有进行类的设计,使用了函数式编程,代码没有体现OOP的特性。函数可复用性也很差,基本都是硬编码出来的垃圾代码。给后续的迭代造成了很大的麻烦。
第一次迭代
题目描述:
类图:同样没有进行类的设计。
源码(源码太长,这里只给出Main方法):
public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); String line = in.nextLine(); try { int coi = Integer.parseInt(line.substring(0, 1)); if (coi < 1 || coi > 5) { System.out.print("Wrong Format"); System.exit(0); } switch (coi) { case 1: judgeTriangle(line.substring(2)); break; case 2: calculateAttribute(line.substring(2)); break; case 3: judgeAngle(line.substring(2)); break; case 4: System.out.println("The point is on the edge of the triangle"); break; case 5: System.out.println("in the triangle"); break; } } catch (Exception e) { System.out.print("Wrong Format"); System.exit(0); } } }
分析:由于第一次使用了函数式的编程,没有做类的设计,在时间紧张的情况下我只能对第一次的代码进行更改和扩充。这导致编码过程非常痛苦,每一个函数的内聚性都不高,几乎需要重写每一个函数。没有进行类的设计浪费了我大量的时间。
第二次迭代:
题目描述:
类图:
分析:
设计了点,线和四边形类,对它们进行了封装。设计ParseInput类对输入进行处理,得到整洁的数据,方便之后的运算。在四边形类中,将四个点作为其的私有属性,设置check方法检测自身能否成为四边形,以及判断是否为特殊四边形的方法。在Line类中,将两个Point对象作为其私有属性,设置getSlope方法,与hasSlope方法共同获取斜率。添加isOnline(Point point), isBetween(Point point)和isSameSide(Point point)方法来判断点与直线的关系。isParallel(Line line)方法判断两条直线的关系。
心得:
通过两次迭代,我切实体会到了先设计再编码的重要性了。不通过严谨设计写出来的代码,不用谈什么面向对象程序设计原则,也不存在什么可扩展性。一时追求解题速度可能后面要花上几倍,几十倍的时间来重构代码。不如在编写之前就做好设计,也许刚开始进度会比别人慢,但是越迭代到后期,每一次的工作量就会比硬编码少得多。
链表练习
源码:
class LinkedList<E> implements LinearLIstInterface<E> { private Node<E> last; private Node<E> first; private int length; public LinkedList() { this.length = 0; last = new Node<>(); first = new Node<>(); } @Override public boolean isEmpty() { return length == 0; } @Override public int size() { return length; } public void addFirst(E o) { if(this.isEmpty()) { this.first = new Node<>(o); this.last = this.first; } else { Node<E> temp = new Node<>(o); temp.setNext(first); this.first = temp; } length++; } public void addLast(E o) { if (this.isEmpty()) { addFirst(o); } else { Node<E> temp = new Node<>(o); last.setNext(temp); last = temp; length++; } } @Override public void add(E o) { if (this.isEmpty()) { addFirst(o); } else { addLast(o); } } @Override public void printList() { Node<E> loop = first; System.out.print("[ "); while (loop != null) { System.out.print(loop.getO().toString() + " "); loop = loop.getNext(); } System.out.println("]"); } @Override public void add(int index, E o) { if ( index < 0 || index > length - 1) { System.out.println("Wrong Index"); System.exit(0); } if (index == 0) { addFirst(o); } else if (index == length - 1) { addLast(o); } else { int pos = 0; Node<E> loop = first; while (loop != null) { if ( pos + 1 == index) { Node<E> temp = new Node<>(o); temp.setNext(loop.getNext()); loop.setNext(temp); break; } pos++; loop = loop.getNext(); } } length++; } @Override public void remove(int index) { if ( index < 0 || index > length - 1) { System.out.println("Wrong Index"); System.exit(0); } int pos = 0; Node<E> loop = first; while (loop != null) { if (pos + 1 == index) { loop.setNext(loop.getNext().getNext()); break; } else { pos++; } loop = loop.getNext(); } length--; } @Override public E get(int index) { if (index < 0 || index > length - 1) { System.out.println("Wrong Index"); System.exit(0); } int pos = 0; for (Node<E> loop = first; loop.getNext() == null; loop = loop.getNext()) { if (pos == index) { return loop.getO(); } pos++; } return null; } }
期中考试题目总结
第一题:
题目描述:
类图:
分析:由于给出了类图,当时写题得时候非常快,照着类图写就是了,没什么大问题。
第二题
题目描述:
类图:
分析:这一题的关键就是把Element类抽象出来,再通过子类复写父类方法实现多态。
第三题:
题目描述:
源码:
import java.util.ArrayList; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); double x1; double y1; double x2; double y2; String color; GeometryObject geometryObject = new GeometryObject(); int choice = in.nextInt(); while(choice != 0){ switch(choice) { case 1: x1 = in.nextDouble(); y1 = in.nextDouble(); if (x1 < 0 || x1 > 200 || y1 < 0 || y1 > 200) { System.out.println("Wrong Format"); System.exit(0); } else geometryObject.add(new Point(x1, y1)); //insert Point object into list break; case 2:x1 = in.nextDouble(); y1 = in.nextDouble(); x2 = in.nextDouble(); y2 = in.nextDouble(); color = in.next(); if (x1 < 0 || x1 > 200 || y1 < 0 || y1 > 200 || x2 < 0 || x2 > 200 || y2 < 0 || y2 > 200) { System.out.println("Wrong Format"); System.exit(0); } else geometryObject.add(new Line(new Point(x1, y1), new Point(x2, y2), color));//insert Line object into list break; case 3:color = in.next(); geometryObject.add(new Plane(color));//insert Plane object into list break; case 4:int index = in.nextInt(); if (index > geometryObject.getList().size() || index < 1){ choice = in.nextInt(); continue; } geometryObject.remove(index - 1);//delete index - 1 object from list break; } choice = in.nextInt(); } for(Element element:geometryObject.getList()){ element.display(); } } } abstract class Element { public abstract void display(); } class Point extends Element { private double x; private double y; public Point(double x, double y) { this.x = x; this.y = y; } public double getX() { return x; } public void setX(double x) { this.x = x; } public double getY() { return y; } public void setY(double y) { this.y = y; } @Override public void display() { System.out.printf("(%.2f,%.2f)%n", x, y); } } class Line extends Element { private Point point1; private Point point2; private String color; public Line(Point point1, Point point2, String color) { this.point1 = point1; this.point2 = point2; this.color = color; } public Point getPoint1() { return point1; } public void setPoint1(Point point1) { this.point1 = point1; } public Point getPoint2() { return point2; } public void setPoint2(Point point2) { this.point2 = point2; } public double getDistance() { return Math.sqrt((getPoint1().getX() - getPoint2().getX()) * (getPoint1().getX() - getPoint2().getX()) + (getPoint1().getY() - getPoint2().getY()) * (getPoint1().getY() - getPoint2().getY())); } public String getColor() { return color; } public void setColor(String color) { this.color = color; } @Override public void display() { System.out.println("The line's color is:" + color); System.out.println("The line's begin point's Coordinate is:"); point1.display(); System.out.println("The line's end point's Coordinate is:"); point2.display(); System.out.printf("The line's length is:%.2f%n", getDistance()); } } class Plane extends Element { private String color; public Plane(String color) { this.color = color; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } @Override public void display() { System.out.println("The Plane's color is:" + color); } } class GeometryObject{ private ArrayList<Element> list = new ArrayList<>(); public GeometryObject() { } public GeometryObject(ArrayList<Element> list) { this.list = list; } public ArrayList<Element> getList() { return list; } public void setList(ArrayList<Element> list) { this.list = list; } public void add(Element element){ list.add(element); } public void remove(int index){ list.remove(index); } }
类图:
分析:GeometryObject类中有用到泛型和ArrayList数据类型,在Main方法中使用了foreach循环。
踩坑心得:
先动笔再动手!先动笔再动手!先动笔再动手!后期改代码真的是折磨,如果前期做好类的设计,只要需求大体不变,迭代起来非常轻松。
总结:
掌握一些基本的数据结构用法,浅学了一下Java FX,还有几种设计模式,以及lambda表达式和Stream 的简单使用。觉得自己还是需要加强类设计的能力,有时长时间设计不出来类图,非常难受,有时类的设计又太过复杂,很难实现。在设计类和害怕设计的太过复杂之中患得患失。所以有必要加强一下设计能力。