java題目集1-3的總結
前言
在pta題目集1-3中,題目集一的題量較另外兩個比較多,但是難度低,考察的是Java的一些基本語法語句(選擇語句)和實用資料的使用,根據之前學C面向過程的知識儲量基本上能夠完成該題目集,做題時主要注意java的double型別資料使用時的精度(第二、八題)和計算時存在誤差(第七題),需要格外注意輸出格式和計算等值時的誤差分析。
題目集二的題量只有三題,難度適中,主要考察的是Java的String格式型別的使用、判斷與轉換,根據之前使用String的相關知識還是能夠完成,其中第二題的串列埠字元解析題需要理解題目意思並查詢相關資料瞭解奇偶效驗位的定義,最後成功地完成題目集。
題目集三的題量也只有三題,但難度卻感覺與前兩個題目集相比,難度直接成幾何倍數增長,並且其中的題目基本上是一題連線著一題的知識點,環環相扣,考察的是字串,double型別資料計算,面向物件等的相關知識,對於初學Java的我感覺非常具有挑戰,做題目前翻閱java課本以及在csdn網站上尋找其中相關資料格式、語法知識的使用,再進行不斷地嘗試編寫程式碼和編譯執行,但第三個題目的30個測試點選項五的兩個測試點始終無法通過,測試樣例通過但是測試點未通過。
設計與分析
題目集一:
7-7 判斷三角形型別(10分)
輸入三角形三條邊,判斷該三角形為什麼型別的三角形。
輸入格式:
在一行中輸入三角形的三條邊的值(實型數),可以用一個或多個空格或回車分隔,其中三條邊的取值範圍均為[1,200]。
輸出格式:
(1)如果輸入資料非法,則輸出“Wrong Format”;
(2)如果輸入資料合法,但三條邊不能構成三角形,則輸出“Not a triangle”;
(3)如果輸入資料合法且能夠成等邊三角形,則輸出“Equilateral triangle”;
(3)如果輸入資料合法且能夠成等腰直角三角形,則輸出“Isosceles right-angled triangle”;
(5)如果輸入資料合法且能夠成等腰三角形,則輸出“Isosceles triangle”;
(6)如果輸入資料合法且能夠成直角三角形,則輸出“Right-angled triangle”;
(7)如果輸入資料合法且能夠成一般三角形,則輸出“General triangle”。
度量分析:
這題比較簡單,整體的思路和題目含義清晰,不需要使用面向物件建立多個類去完成,只需要Main類就能實功能,先判定出正確格式,然後不斷使用if-else語句不斷判斷篩選,得出相應的輸出。
主要程式碼分析:
if(a<1||a>200||b<1||b>200||c<1||c>200){ System.out.println("Wrong Format"); } else{ if((a+b)<=c||(a+c)<=b||(b+c)<=a){ System.out.println("Not a triangle"); } else{ if(a==b&&a==c&&b==c){ System.out.println("Equilateral triangle"); } else if((a==b&&Math.abs(c*c-a*a-b*b)<0.00001)||(a==c&&Math.abs(b*b-a*a-c*c)<0.00001)||(c==b&&Math.abs(a*a-c*c-b*b)<0.00001)){ System.out.println("Isosceles right-angled triangle"); } else if(a==b||a==c||b==c){ System.out.println("Isosceles triangle"); } else if(a*a==b*b+c*c||b*b==a*a+c*c||c*c==a*a+b*b){ System.out.println("Right-angled triangle"); } else{ System.out.println("General triangle"); } } }
程式碼思路:使用if-else語句,先判斷該三角形輸入的資料是否合法(1-200),合法的話再判斷是否能構成三角形(兩邊之和大於第三邊的定理),如果能構成三角形,再判斷是等邊三角形或者等腰直角三角形或者等腰三角形或者直角三角形或者一般三角形,其中判斷等腰直角三角形的時候,double型別資料計算時會丟失部分精度,所以需要算上誤差,並使用了Math.abs函式算成絕對值進行比較,得出是否為等腰直角三角形的判斷結果。
優缺點:
優點:1.整體if-else語句的判斷條件比較清晰,便於理解,並且可操作性強。
2.能夠考慮到直角三角形的邊長可能存在無理數,會產生誤差,影響精度,故使用Math.abs(c*c-a*a-b*b)<0.00001,讓判斷結果更精確。
缺點:1.if-else語句的使用過多,導致程式碼繁雜。
2.判定是否為直角三角形時未測試其計算精度,導致判斷結果有誤差,一些無理數邊長資料被省略。
3.等腰直角三角形和等腰三角形、直角三角形的部分條件重合,但只能輸出一個三角形型別,輸出不嚴謹且這三個三角形型別的輸出順序不能確認,使得部分輸出樣例有偏差。
題目集二:
7-2 串列埠字元解析 (40 分)
RS232是串列埠常用的通訊協議,在非同步通訊模式下,串列埠可以一次傳送5~8位資料,收發雙方之間沒有資料傳送時線路維持高電平,相當於接收方持續收到資料“1”(稱為空閒位),傳送方有資料傳送時,會在有效資料(5~8位,具體位數由通訊雙方提前設定)前加上1位起始位“0”,在有效資料之後加上1位可選的奇偶校驗位和1位結束位“1”。請編寫程式,模擬串列埠接收處理程式,注:假定有效資料是8位,奇偶校驗位採用奇校驗。
輸入格式:
由0、1組成的二進位制資料流。例如:11110111010111111001001101111111011111111101111
輸出格式:
過濾掉空閒、起始、結束以及奇偶校驗位之後的資料,資料之前加上序號和英文冒號。
如有多個數據,每個資料單獨一行顯示。
若資料不足11位或者輸入資料全1沒有起始位,則輸出"null data",
若某個資料的結束符不為1,則輸出“validate error”。
若某個資料奇偶校驗錯誤,則輸出“parity check error”。
若資料結束符和奇偶校驗均不合格,輸出“validate error”。
如:11011或11111111111111111。
例如:
1:11101011
2:01001101
3:validate error
該題目是對串列埠字元解析,整體題目結構不復雜,故也不需要建立多個類進行解答,只需使用Main類。首先得對該題目進行詳細的分析,經過查詢相關奇偶效驗性的含義,明白奇偶效驗是判斷“1”的個數為奇數還是偶數,並是採用的是奇效驗,判定的資料段為有效資料和其後一位計算判定,再運用for迴圈語句,if-else語句,變數識別符號,解答該題目。
主要程式碼分析:
if(b.length<11){ x=1; } else{ String c="1"; for(int i=1;i<b.length;i++){ c=c+1; } if(c.equals(a)){ x=1; } } if(x==1){ System.out.println("null data"); } else{ for(int k=0;k<b.length;k++){ if(b[k]=='0'){ for(int j=k+1;j<=k+9;j++){ if(b[j]=='1'){ z=z+1; } } if(b[k+10]!='1'){ System.out.println(y+":"+"validate error"); y++; k=k+10; z=0; continue; } else if(z%2==0){ System.out.println(y+":"+"parity check error"); y++; k=k+10; z=0; continue; } else if(b[k+10]!='1'&&z%2==0){ System.out.println(y+":"+"validate error"); y++; k=k+10; z=0; continue; } else{ System.out.print(y+":"); for(int t=k+1;t<k+9;t++){ System.out.print(b[t]); } System.out.println(); y++; k=k+10; z=0; continue; } } } }
程式碼思路:先用if-else語句和for語句以x為識別符號,判斷輸入資料格式是否錯誤,如果正確再用for語句對輸入的字串進行解析,利用z來計算“1”的個數進行奇偶效驗,每次輸出一個結果後,y+1來表示下一結果的順序,k+10來略過解析完的字串段,使用continue保證進行下一次的迴圈,最後對每段字元的判斷若某個資料的結束符不為1,則輸出“validate error”。若某個資料奇偶校驗錯誤,則輸出“parity check error”。若資料結束符和奇偶校驗均不合格,輸出“validate error”。得出相應的結果。
優缺點:
優點:1.for語句迴圈中,使用了continue,保證了下一次迴圈的進行。
2.能夠較為精準的對字串解析,並依照題意得出對應結果。
缺點:1.if-else語句與前面題目集7-7一樣依舊使用過多,造成程式繁雜。
2.識別符號多,並且使用巢狀迴圈,不易於閱讀者理解。
題目集三:
7-1 點線形系列1-計算兩點之間的距離 (10 分)
輸入連個點的座標,計算兩點之間的距離
輸入格式:
4個double型別的實數,兩個點的x,y座標,依次是x1、y1、x2、y2,兩個點的座標之間以空格分隔,每個點的x,y座標以英文“,”分隔。例如:0,0 1,1或0.1,-0.3 +3.5,15.6。
若輸入格式非法,輸出"Wrong Format"。
若輸入格式合法但座標點的數量超過兩個,輸出“wrong number of points”。
輸出格式:
計算所得的兩點之間的距離。例如:1.4142135623730951
度量分析:
該題目整體思路清晰,只需建立一個Point類(點),主要注意的地方是判斷輸入格式非法的地方要嚴謹準確(討論多種情況),建立一個find方法來判斷輸入格式,使用新學習的split方法進行分割字串,il-else語句等,判斷輸入格式合法且沒超過2個點後輸出距離。
主要程式碼分析:
public static int find(String a){ char b[]=a.toCharArray(); for(int i=0;i<b.length;i++){ if(i<=b.length-2) { if((b[i]=='-'||b[i]=='+'||b[i]=='.')&&(b[i+1]=='-'||b[i+1]=='+'||b[i+1]=='.')){ return 1; } } if(b[i]!='.'&&b[i]!='-'&&b[i]!='+'&&(b[i]<'0'||b[i]>'9')){ return 1; } if(b[i]=='0'&&b[i+1]!='.'){ return 1; } } if(b[b.length-1]=='.'||b[0]=='.'){ return 1; } return 0; }
程式碼思路:此為find方法,返回值為int型別,用以判斷輸入資料的合法性。將輸入的字串a轉換成為字元陣列b,判斷陣列中除了. - + 0-9外是否還有其它非法字元,如果有返回1,並判斷. - + 0-9的順序是否有問題,如果有返回1,這些情況都沒有出現,則返回0。
優缺點:
優點:1.if-else語句條件簡明,且運用了新學習的tochararray方法和split方法。
缺點:1.使用了許多if-else語句和巢狀迴圈,程式碼繁雜過多,,不簡潔,不易於理解。
2.測試點測試非法格式有許多種情況未考慮到,僅考慮了部分非法格式,不夠完善。
3.未能使用正則表示式,程式過長。
題目集三:
7-2 點線形系列2-線的計算 (42 分)
使用者輸入一組選項和資料,進行與直線有關的計算。選項包括:
1:輸入兩點座標,計算斜率,若線條垂直於X軸,輸出"Slope does not exist"。
2:輸入三個點座標,輸出第一個點與另外兩點連線的垂直距離。
3:輸入三個點座標,判斷三個點是否在一條線上,輸出true或者false。
4:輸入四個點座標,判斷前兩個點所構成的直線與後兩點構成的直線是否平行,輸出true或者false.
5:輸入四個點座標,計算輸出前兩個點所構成的直線與後兩點構成的直線的交點座標,x、y座標之間以英文分隔",",並輸出交叉點是否在兩條線段之內(不含四個端點)的判斷結果(true/false),判斷結果與座標之間以一個英文空格分隔。若兩條線平行,沒有交叉點,則輸出"is parallel lines,have no intersection point"。
輸入格式:
基本格式:選項+":"+座標x+","+座標y+" "+座標x+","+座標y。
例如:1:0,0 1,1
如果不符合基本格式,輸出"Wrong Format"。
如果符合基本格式,但輸入點的數量不符合要求,輸出"wrong number of points"。
不論哪個選項,如果格式、點數量都符合要求,但構成任一條線的兩個點座標重合,輸出"points coincide",
輸出格式:
見題目描述。
度量分析:
該題目跟題目集三7-1的輸入格式判斷非法類似,但是因為7-1我的程式碼判斷不是很完善,所以套入這題出現bug有兩個測試點未通過,經過完善find方法得以通過,並且我對輸入資料的長度和字元數量進行了判斷。該題我建立了Point類(點)和Test類(方法),Point類用於取用其中的方法對應題目的選項。通過Main類,Point類,Test類共同完成該題。
主要程式碼分析:
public static int find(String a){ char b[]=a.toCharArray(); if(b[0]=='0'&&b.length>1){ if(b[1]!='.'){ return 1; } } if(b[0]=='+'||b[0]=='-'){ if(b[1]=='0'&&b.length>2){ if(b[2]!='.'){ return 1; } } if(b[1]<'0'||b[1]>'9'){ return 1; } } for(int k6=0;k6<b.length;k6++){ if(b[k6]==' '||b[k6]==':'){ return 1; } } if(b[b.length-1]=='.'||b[0]=='.'||b[b.length-1]=='+'||b[b.length-1]=='-'){ return 1; } return 0; } public void test1(String a[]){ String a1[]=a[0].split(","); String a2[]=a[1].split(","); Point aa=new Point(a1[0],a1[1]); Point b=new Point(a2[0],a2[1]); if(aa.x==b.x&&aa.y==b.y){ System.out.println("points coincide"); } else{ double s=0; s=(aa.y-b.y)/(aa.x-b.x); if(aa.x==b.x){ System.out.println("Slope does not exist"); } else{ System.out.println(s); } } } public void test2(String a[]){ String a1[]=a[0].split(","); String a2[]=a[1].split(","); String a3[]=a[2].split(","); Point aa=new Point(a1[0],a1[1]); Point b=new Point(a2[0],a2[1]); Point c=new Point(a3[0],a3[1]); if((b.x==c.x&&b.y==c.y)||(aa.x==b.x&&aa.y==b.y)||(aa.x==c.x&&aa.y==c.y)){ System.out.println("points coincide"); } else{ if(b.x==c.x){ System.out.println(Math.abs(aa.x-b.x)); } else if(b.y==c.y){ System.out.println(Math.abs(aa.y-b.y)); } else{ double k=(b.y-c.y)/(b.x-c.x); double b1=b.y-k*b.x; double s=Math.abs(k*aa.x-aa.y+b1)/Math.sqrt(k*k+1); System.out.println(s); } } } public void test3(String a[]){ String a1[]=a[0].split(","); String a2[]=a[1].split(","); String a3[]=a[2].split(","); Point aa=new Point(a1[0],a1[1]); Point b=new Point(a2[0],a2[1]); Point c=new Point(a3[0],a3[1]); if((aa.x==b.x&&aa.y==b.y)||(aa.x==c.x&&aa.y==c.y)||(b.x==c.x&&b.y==c.y)) { System.out.println("points coincide"); } else { if(aa.x==b.x&&b.x==c.x&&aa.x==c.x) { System.out.println("true"); } else if((aa.y-b.y)/(aa.x-b.x)==(aa.y-c.y)/(aa.x-c.x)&&(aa.y-b.y)/(aa.x-b.x)==(b.y-c.y)/(b.x-c.x)&&(b.y-c.y)/(b.x-c.x)==(aa.y-c.y)/(aa.x-c.x)) { System.out.println("true"); } else { System.out.println("false"); } } } public void test4(String a[]){ String a1[]=a[0].split(","); String a2[]=a[1].split(","); String a3[]=a[2].split(","); String a4[]=a[3].split(","); Point aa=new Point(a1[0],a1[1]); Point b=new Point(a2[0],a2[1]); Point c=new Point(a3[0],a3[1]); Point d=new Point(a4[0],a4[1]); if((aa.x==b.x&&aa.y==b.y)||(c.x==d.x&&c.y==d.y)) { System.out.println("points coincide"); } else { if((aa.x==b.x&&c.x==d.x)||(aa.x==b.x&&b.x==c.x&&c.x==d.x)) { System.out.println("true"); } else if((aa.y-b.y)/(aa.x-b.x)==(c.y-d.y)/(c.x-d.x)) { System.out.println("true"); } else { System.out.println("false"); } } } public void test5(String a[]){ String a1[]=a[0].split(","); String a2[]=a[1].split(","); String a3[]=a[2].split(","); String a4[]=a[3].split(","); Point aa=new Point(a1[0],a1[1]); Point b=new Point(a2[0],a2[1]); Point c=new Point(a3[0],a3[1]); Point d=new Point(a4[0],a4[1]); if((aa.x==b.x&&aa.y==b.y)||(c.x==d.x&&c.y==d.y)) { System.out.println("points coincide"); } else { if((aa.x==b.x&&c.x==d.x)||(aa.x==b.x&&b.x==c.x&&c.x==d.x)||(aa.y-b.y)/(aa.x-b.x)==(c.y-d.y)/(c.x-d.x)) { System.out.println("is parallel lines,have no intersection point"); } else { double aa1,aa2,bb1,bb2,c1,c2,m,x,y; aa1=b.y-aa.y; aa2=d.y-c.y; bb1=b.x-aa.x; bb2=d.x-c.x; c1=bb1*aa.y-aa1*aa.x; c2=bb2*c.y-aa2*c.x; m=aa1*bb2-aa2*bb1; x=(bb1*c2-bb2*c1)/m; y=(aa1*c2-aa2*c1)/m; double max1=Math.max(aa.x,b.x); double min1=Math.min(aa.x,b.x); double max2=Math.max(aa.y,b.y); double min2=Math.min(aa.y,b.y); double max3=Math.max(c.x,d.x); double min3=Math.min(c.x,d.x); double max4=Math.max(c.y,d.y); double min4=Math.min(c.y,d.y); if ((x>min1&&x<max1&&y>min2&&y<max2)||(x>min3&&x<max3&&y>min4&&y<max4)) { System.out.println(x+","+y+" true"); } else { System.out.println(x+","+y+" false"); } } } }
程式碼思路:
第一個是find方法,較7-1進行了完善,對一些我本以為已經排除的字元進行再次判斷,並按照輸入資料順序判斷字元順序,最後成功通過遺漏的測試點。
test1方法,void型,用於對應選項一,要特別區分斜率存在和斜率不存在的情況得出相應結果。
test2方法,void型,用於對應選項二,跟test1注意的點一樣。
test3方法,void型,用於對應選項三,三個點x座標相同則true,斜率相同也輸出true,其他情況則輸出false。
test4方法,void型,用於對應選項四,跟test3的原理類似。
test5方法,void型,用於對應選項五,剛開始使用以前學習的方法來求交點座標,但是始終有一個測試點無法通過,後面通過學習csdn上求交點的方法通過了測試點。還要注意題目意思是該交點在兩條線段中的一條內就行。
優缺點:
優點:1.運用point類讓程式結構不會出現太多重複建立點的程式碼,但還是存在一些。
2.對非法格式和選項的方法進行詳細分析,找出多種可能存在的情況。
缺點:1.程式過長,每個方法都建立了大量double型資料,過於繁雜。
2.選項五求交點的方法使用平常數學方法不能通過測試點,需使用另外的方法,測試樣例能通過,但測試點卻無法通過。
3.沒有使用正則表示式匹配輸入格式,程式碼太過於長。
題目集三:
7-3 點線形系列3-三角形的計算 (48 分)
使用者輸入一組選項和資料,進行與三角形有關的計算。選項包括:
1:輸入三個點座標,判斷是否是等腰三角形、等邊三角形,判斷結果輸出true/false,兩個結果之間以一個英文空格符分隔。
2:輸入三個點座標,輸出周長、面積、重心座標,三個引數之間以一個英文空格分隔,座標之間以英文","分隔。
3:輸入三個點座標,輸出是鈍角、直角還是銳角三角形,依次輸出三個判斷結果(true/false),以一個英文空格分隔,
4:輸入五個點座標,輸出前兩個點所在的直線與三個點所構成的三角形相交的交點數量,如果交點有兩個,則按面積大小依次輸出三角形被直線分割成兩部分的面積。若直線與三角形一條線重合,輸出"The point is on the edge of the triangle"
5:輸入四個點座標,輸出第一個是否在後三個點所構成的三角形的內部(輸出in the triangle/outof triangle)。
必須使用射線法,原理:由第一個點往任一方向做一射線,射線與三角形的邊的交點(不含點本身)數量如果為1,則在三角形內部。如果交點有兩個或0個,則在三角形之外。若點在三角形的某條邊上,輸出"on the triangle"
輸入格式:
基本格式:選項+":"+座標x+","+座標y+" "+座標x+","+座標y。點的x、y座標之間以英文","分隔,點與點之間以一個英文空格分隔。
輸出格式:
基本輸出格式見每種選項的描述。
異常情況輸出:
如果不符合基本格式,輸出"Wrong Format"。
如果符合基本格式,但輸入點的數量不符合要求,輸出"wrong number of points"。
如果輸入的三個點無法構成三角形,輸出"data error"。
注意:輸出的資料若小數點後超過6位,只保留小數點後6位,多餘部分採用四捨五入規則進到最低位。小數點後若不足6位,按原始位數顯示,不必補齊。例如:1/3的結果按格式輸出為 0.333333,1.0按格式輸出為1.0
選項4中所輸入線的兩個點座標重合,輸出"points coincide",
度量分析:
該題目看起來容易,做起來卻不盡如人意,判斷非法格式判斷方面套以7-2的方法改變點的數量和資料格式長度等,能夠通過測試點測試樣例。我建立了Point類和Triangle類,Triangle類裡建立了匹配選項1-5的方法和需要使用的一些方法,並引用Point類建立的點,選項二和四輸出的資料需要四捨五入並且保留至小數點後六位,通過在網上查詢四捨五入的方法,通過先轉換成字串,再判斷是否超過六位小數點,對其進行四捨五入,再輸出資料。選項三輸出三角形同樣因為精度問題需要比較其誤差,而選項五耗費很長時間編寫的程式碼通過其測試樣例,但始終無法通過測試點,更改了多種方法還是無法完成那兩個測試點。
主要程式碼分析:
class Triangle{ double a1,b1,c1; Triangle(){ } void test1(Point a,Point b,Point c) { int x=0,y=0; a1=d(a.x,a.y,b.x,b.y); b1=d(a.x,a.y,c.x,c.y); c1=d(b.x,b.y,c.x,c.y); if((a.x==b.x&&a.y==b.y)||(a.x==c.x&&a.y==c.y)||(c.x==b.x&&c.y==b.y)) { System.out.println("data error"); } else { if(a1==b1&&b1==c1) { y=1; } if(a1==b1||a1==c1||b1==c1) { x=1; } if(x==1&&y==1) { System.out.println("true true"); } else if(x==1&&y==0) { System.out.println("true false"); } else if(x==0&&y==1) { System.out.println("false true"); } else { System.out.println("false false"); } } } void test2(Point a,Point b,Point c) { double S,C,x1,y1; a1=d(a.x,a.y,b.x,b.y); b1=d(a.x,a.y,c.x,c.y); c1=d(b.x,b.y,c.x,c.y); if((a.x==b.x&&a.y==b.y)||(a.x==c.x&&a.y==c.y)||(c.x==b.x&&c.y==b.y)) { System.out.println("data error"); } else { C=a1+b1+c1; double xx=d(b.x,b.y,c.x,c.y); S=dd(a,b,c)*xx/2; x1=(a.x+b.x+c.x)/3; y1=(a.y+b.y+c.y)/3; String result1= change(C); String result2= change(S); String result3= change(x1); String result4= change(y1); System.out.println(result1+" "+result2+" "+result3+","+result4); } } void test3(Point a,Point b,Point c) { a1=d(a.x,a.y,b.x,b.y); b1=d(a.x,a.y,c.x,c.y); c1=d(b.x,b.y,c.x,c.y); if((a.x==b.x&&a.y==b.y)||(a.x==c.x&&a.y==c.y)||(c.x==b.x&&c.y==b.y)) { System.out.println("data error"); } else { double max=getmax(a1,b1,c1); if(max==a1) { sjx(b1,c1,max); } else if(max==b1) { sjx(a1,c1,max); } else { sjx(a1,b1,max); } } } void test4(Point a,Point b,Point c,Point d,Point e) { int i=0; if(a.x==b.x&&b.y==a.y) { System.out.println("points coincide"); } else if((c.x==d.x&&c.y==d.y)||(c.x==e.x&&c.y==e.y)||(d.x==e.x&&d.y==e.y)){ System.out.println("data error"); } else { int a1=0,a2=0; Point p1=getpoint(a,b,c,d); Point p2=getpoint(a,b,c,e); Point p3=getpoint(a,b,d,e); i=panduan(p1)+panduan(p2)+panduan(p3); if((p1!=null&&p2!=null&&p1.x==p2.x&&p1.y==p2.y)||(p1!=null&&p3!=null&&p1.x==p3.x&&p1.y==p3.y)) { i--; a1=1; } if(p2!=null&&p3!=null&&p2.x==p3.x&&p2.y==p3.y) { i--; a2=1; } if(i<2) { System.out.println(i); } else if(i==2) { if(panduan(p1)==0||a1==1) { double xx=d(d.x,d.y,e.x,e.y); double s=dd(c,d,e)*xx/2; double xx1=d(p2.x,p2.y,p3.x,p3.y); double s1=dd(e,p2,p3)*xx1/2; double s2=s-s1; double max=Math.max(s1, s2); String result1= change(s2); String result2= change(max); String result3= change(s1); if(max==s1) { System.out.println(i+" "+result1+" "+result2); } else { System.out.println(i+" "+result3+" "+result2); } } else if(panduan(p2)==0||a2==1) { double xx=d(d.x,d.y,e.x,e.y); double s=dd(c,d,e)*xx/2; double xx1=d(p1.x,p1.y,p3.x,p3.y); double s1=dd(d,p1,p3)*xx1/2; double s2=s-s1; double max=Math.max(s1, s2); String result1= change(s2); String result2= change(max); String result3= change(s1); if(max==s1) { System.out.println(i+" "+result1+" "+result2); } else { System.out.println(i+" "+result3+" "+result2); } } else if(panduan(p3)==0) { double xx=d(d.x,d.y,e.x,e.y); double s=dd(c,d,e)*xx/2; double xx1=d(p1.x,p1.y,p2.x,p2.y); double s1=dd(c,p1,p2)*xx1/2; double s2=s-s1; double max=Math.max(s1, s2); String result1= change(s2); String result2= change(max); String result3= change(s1); if(max==s1) { System.out.println(i+" "+result1+" "+result2); } else { System.out.println(i+" "+result3+" "+result2); } } } else { System.out.println("The point is on the edge of the triangle"); } } } void test5(Point a,Point b,Point c,Point d) { if((b.x==c.x&&b.y==c.y)||(b.x==d.x&&b.y==d.y)||(d.x==c.x&&d.y==c.y)) { System.out.println("data error"); } else { if((pan(a,b,c)==1&&(b.x!=c.x)&&pan1(a,b,c)==1)||(pan(a,b,d)==1&&(b.x!=d.x)&&pan1(a,b,d)==1)||(pan(a,c,d)==1&&(c.x!=d.x)&&pan1(a,c,d)==1)) { System.out.println("on the triangle"); } else if((b.x==c.x&&a.x==b.x&&pan(a,b,c)==1)||(b.x==d.x&&a.x==b.x&&pan(a,b,d)==1)||(c.x==d.x&&a.x==c.x&&pan(a,c,d)==1)) { System.out.println("on the triangle"); } else { double s1,s2,s3,S; double x1=d(b.x,b.y,c.x,c.y); s1=dd(a,b,c)*x1/2; double x2=d(b.x,b.y,d.x,d.y); s2=dd(a,b,d)*x2/2; double x3=d(c.x,c.y,d.x,d.y); s3=dd(a,c,d)*x3/2; double xx=d(c.x,c.y,d.x,d.y); S=dd(b,c,d)*xx/2; if(s1+s2+s3-S<0.00001) { System.out.println("in the triangle"); } else { System.out.println("outof the triangle"); } } } } int pan(Point a,Point b,Point c) {//判斷a是否在b,c點範圍內 double max1=Math.max(b.x,c.x); double min1=Math.min(b.x,c.x); double max2=Math.max(b.y,c.y); double min2=Math.min(b.y,c.y); if(a.x>=min1&&a.x<=max1&&a.y>=min2&&a.y<=max2) { return 1; } return 0; } int pan1(Point a,Point b,Point c) {//判斷a點是否在b,c點連線的直線上 double k1=(b.y-c.y)/(b.x-c.x); double b1=b.y-k1*b.x; if((k1*a.x)-a.y+b1==0) { return 1; } return 0; } double d(double a,double b,double c,double d) {//計算兩點間的距離 return Math.sqrt(Math.pow(a-c, 2)+Math.pow(b-d, 2)); } String change(double x) {//改變資料位數 String a=String.valueOf(x); if(a.length()>6) { return String.format("%.6f",x); } return a; } void sjx(double a,double b,double max) {//判斷該三角形為什麼型別 if((a*a+b*b)-max*max<-0.00001) { System.out.println("true false false"); } else if(Math.abs((a*a+b*b)-max*max)<0.00001) { System.out.println("false true false"); } else { System.out.println("false false true"); } } double getmax(double a,double b,double c){//求三個數的最大值 double max=a; if(max<b) { max=b; } if(max<c) { max=c; } return max; } Point getpoint(Point a,Point b,Point c,Point d) {//計算交點 if((a.x==b.x&&c.x==d.x)||(a.x==b.x&&b.x==c.x&&c.x==d.x)||(a.y-b.y)/(a.x-b.x)==(c.y-d.y)/(c.x-d.x)) { return null; } else { double aa1,aa2,bb1,bb2,c1,c2,m,x,y; aa1=b.y-a.y; aa2=d.y-c.y; bb1=b.x-a.x; bb2=d.x-c.x; c1=bb1*a.y-aa1*a.x; c2=bb2*c.y-aa2*c.x; m=aa1*bb2-aa2*bb1; x=(bb1*c2-bb2*c1)/m; y=(aa1*c2-aa2*c1)/m; double max3=Math.max(c.x,d.x); double min3=Math.min(c.x,d.x); double max4=Math.max(c.y,d.y); double min4=Math.min(c.y,d.y); if ((x>=min3&&x<=max3&&y>=min4&&y<=max4)) { return new Point(x,y); } else { return null; } } } int panduan(Point a) {//判斷是否存在交點 if(a==null) { return 0; } else return 1; } double dd(Point a,Point b,Point c) {//求點到直線的距離 double d; if(b.x==c.x) { d=Math.abs(a.x-b.x); } else { d=Math.abs(((b.y-c.y)/(b.x-c.x))*a.x-a.y+b.y-b.x*((b.y-c.y)/(b.x-c.x)))/Math.sqrt(Math.pow((b.y-c.y)/(b.x-c.x),2)+1); } return d; } }
程式碼思路:
test1方法簡單,只需進行正常的邊長比較。test2輸出資料時需要注意格式,算重心座標直接使用數學公式套用,test3類似與前面題目的三角形型別判斷,使用了a平方b平方c平方關係的比較,不過測定資料更加嚴謹,對三種情況都有誤差的檢驗。test4我使用的求交點方法會計算出重複交點,所以運用了識別符號進行排除。test5計算點重合和是否在三角形邊上大概都過了測試點,而到了計算在三角形內部還是外部時候,由於對射線法不是很能理解,使用別的方法,但是始終無法通過選項五判斷的全部測試點。
優缺點:
優點:1.對每個方法的計算嚴謹,儘量減少了存在的誤差。
2.使用了面向過程,建立多個類,進行協同完成。
缺點:1.沒有使用正則表示式,程式碼過於繁瑣。
2.對選項五的測試點無法通過,不能使用射線法進行解題。
採坑心得
題目集一 7-7:
此題目唯一容易失分的就是未對double型別資料計算精度的把握,使用勾股定理進行計算判斷直角三角形會存在誤差,使用以後遇到類似判斷直角三角形乃至double型資料計算時需要算其精度,把握誤差,可以將誤差設為0.00001或者更小。
題目集二 7-2:
此題目奇偶效驗性判斷的時候要注意不僅有效資料還有有效資料後一位,共九位都需要進行判斷,並且這個是巢狀迴圈,使用每判斷完一串有效資料後k需要加10,進行下一段字串的判斷,這個坑就是需要注意迴圈時資料判斷位數準確,並且要正確理解題目含義。
題目集三 7-1:
該題目判斷非法格式時,對格式的判斷過於複雜且不夠正確,使用了許多if語句,導致程式碼太長,對整個輸入格式的考慮不周全,容易存在隱患。所以以後做類似非法格式判斷的題目應該學習正則表示式用來判斷輸入格式的合法性,減少過多的程式碼,讓整個程式都看起來簡潔明瞭,注意輸入格式字元的前後順序。
題目集三 7-2:
1.用前一題的非法判斷方法發現無法通過全部測試點存在bug,所以對find方法進行改進。此處坑點在於我們對輸入格式判斷時應該循循漸進,可以一位連著一位判斷,避免有遺漏的情況發生。
2.在對選項五計算交點時候,運用平常所學的求交點座標貌似行不通無法通過兩個測試點,我通過網上查詢方法才找尋到這個能夠過測試點求交點的方法。故我們應該多學習演算法,不要糾結於一種演算法或只掌握一種演算法。以後遇到此類算交點的題目時可採用這種方法。
題目集三 7-3:
1.此部分與前面求三角形型別的相似,我一開始只是把握了直角三角形的精度,但是有測試點未通過,然後我就增加了其他判斷時的精度,最後通過了測試點。這題精度不僅計算了直角三角形,還涉及鈍角三角形的精度,所以以後對於double型都應該注意精度,來確保準確性。
2.因為不會射線法,我通過使用面積法來判斷點在內部還是外部,用這種方法我輸入5:0.5,0.5 0,0 0,2 4,0能夠輸出in the triangle,輸入5:0,0 -1,-1 2,3 3,4能夠輸出outof the triangle,兩個測試樣例都通過了,但是有兩個測試點卻始終無法通過,於是更改了多張方法還是無法通過。此處坑點在於該題應該設定了測試射線法的點,故使用其他方法無法通過,應該學習射線法去完成題目。
改進建議
題目集一7-7和題目集二7-2:
由SourceMonitor以及PowerDesigner軟體測評結果可以得知,程式碼複雜度過高,使用了太多if-else語句,且只有一個Main類,建議減少使用if-else語句,並且可以使用switch語句來減少使用,可以建立輸出類和判斷類,進行多種類互動。
題目集三7-1、題目集三7-2和題目集三7-3:
由SourceMonitor的評測圖以及PowerDesigner軟體測評結果可以可知,這幾個題目的圈複雜度之高,因為使用的是普通的if-else語句,並且類設計的也十分簡陋,大致跟面向過程差不多,應該使用switch語句進行選項進行選擇的判斷,並且可以再建立方法類和線類,進行互動使用,讓複雜度降低,讓程式碼簡潔明瞭。我寫的程式碼與程式碼間關係過於簡單,也沒有使用正則表示式,程式碼太過繁雜,在以後的學習中,做此類題目應該使用正則表示式降低程式碼繁雜和複雜度,也要多將類與類之間的關係進行呼叫,體現java面向物件的特點。
總結
java這階段的學習,老師主要講的是物件與類和麵向物件的兩章,學習的都是java的基礎知識,但是卻是java的奠基石,只有學好這些基礎的類知識,才能為後面更好的學習做準備,讓我從之前學C語言的習慣改到面向物件的java,我對java的瞭解還很淺顯,需要學習更多的結構、語法知識來充實java的學習。
這幾次的題目集,讓我明白了許多還需要提高的地方:
1.垃圾程式碼過多,因為不熟悉類與類之間的關係和呼叫,使用過多語句,程式碼太過複雜,寫的程式碼質量低,要懂得多運用類與類的關係。
2.多用switch語句,減少if-else語句的使用,這幾次程式碼複雜度都很高,要寫的更加簡潔。
3.使用正則表示式來解決一些非法格式判斷問題,使用平常方法程式碼繁雜且效率低,而正則表示式能夠將輸入的字串快速判斷。
4.上課認真聽課,課後也需要自己多瞭解java的知識,畢竟老師一般教基礎知識,許多知識還需要自學,多鞏固基礎函式語法知識,許多都與C語言類似,更易於理解和吸收,防止在平常編寫程式碼時忘記一些基礎知識。