前言:
這三週的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 的簡單使用。覺得自己還是需要加強類設計的能力,有時長時間設計不出來類圖,非常難受,有時類的設計又太過複雜,很難實現。在設計類和害怕設計的太過複雜之中患得患失。所以有必要加強一下設計能力。