PTA-oop第一次博客2020.9.27
一.前言
题目集一:
作为初学Java时做的第一份作业,本次题目集的题目数量不算很少,但是难度都属于偏低的一类,其中基本上包含了Java中所有的基础语法,我认为本次题目集的目的只是让我们熟悉Java的语法以及书写方式,为接下来的的学习打下良好的基础
题目集二:
本次作业集题目量少,同样和题目集一一样难度依然不高,属于让我们熟悉Java中字符串的有关操作,Java中对于字符串所能进行操作的简便性是c语言远远比不上的
题目集三:
第三次作业较前两次作业在难度上有了很高的提升,虽然只有三个题,但是这三个题目是环环相扣的,这样就导致我在写这次作业时花费时间较多.同样的对于知识量考验也有了质的提高,最明显的就是测试点增加了,自己想不到的情况也增加了
二.设计与分析
题目一:
nchu-software-oop-2022-2
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”。
import java.util.Scanner; public class Main { public static void main(String[] arges){ Scanner input = new Scanner(System.in); int num=1; String str= input.nextLine(); int length=str.length(); if(!judgeNull(str,length)) { System.out.print("null data"); return; } while(length>=11) { int start=getStart(str); String substr = str.substring(start,start+8); if(oddParity(str,substr,start)==0||oddParity(str,substr,start)==2&&!judgeEnd(str,start)||!judgeEnd(str,start)) System.out.println(num+":"+"validate error"); else if(oddParity(str,substr,start)==2) System.out.println(num+":"+"parity check error"); else System.out.println(num+":"+substr); num++; str=str.substring(start+10); length=str.length(); } } public static boolean judgeNull(String str,int length) { int index=str.indexOf('0'); if(length<11||index==-1) return false; else return true; } public static int getStart(String str) { return str.indexOf('0')+1; } public static int oddParity(String str,String substr,int start) { int i,count=0; char thischar; for(i=0;i<8;i++) { thischar=substr.charAt(i); if(thischar=='1') count++; } if(start+9>str.length()) return 0;//没有奇偶校验位和结束位 if(count%2==0&&str.charAt(start+8)=='1'||count%2!=0&&str.charAt(start+8)=='0') return 1;//奇校验正确 else return 2;//济礁岩不正确 } public static boolean judgeEnd(String str,int start) { if(start+10>str.length()||str.charAt(start+9)!='1') return false; else return true; } }


由于代码难度较小,长度也比较短,最大圈复杂度为0,以及代码深度也在正常范围
题目二:
作业二 7-2
nchu-software-oop-2022-3
输入连个点的坐标,计算两点之间的距离
输入格式:
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
import java.util.Scanner; public class Main { static double x1; static double y1; static double x2; static double y2; public static void main(String[] args) { Scanner input=new Scanner(System.in); String S=input.nextLine(); String regx="([+-]?[1-9][0-9]*\\.[0-9]+)|([+-]?0\\.[0-9]+)|([+-]?[1-9][0-9]*)|(0)"; String arr[]=S.split(" "); if(arr.length>2) { System.out.print("wrong number of points"); return; } String arr2[]=arr[0].split(","); if(matches(arr2[0])&&matches(arr2[1])) { x1=Double.parseDouble(arr2[0]); y1=Double.parseDouble(arr2[1]); } else { System.out.print("Wrong Format"); return; } String arr3[]=arr[1].split(","); if(matches(arr3[0])&&matches(arr3[1])) { x2=Double.parseDouble(arr3[0]); y2=Double.parseDouble(arr3[1]); } else { System.out.print("Wrong Format"); return; } System.out.print(Math.sqrt(Math.pow(x1-x2,2)+Math.pow(y1-y2,2))); } public static boolean matches(String arr) { String regx="([+-]?[1-9][0-9]*\\.[0-9]+)|([+-]?0\\.[0-9]+)|([+-]?[1-9][0-9]*)|(0)"; if(arr.matches(regx)) return true; else return false; } }

这是第三次作业中第一道题目,难度不大,在写这道题目时没有用到面向对象的方法,仅仅使用了一个主类,内容是按照面向过程来写,但是由于代码简单,其中的代码深度和复杂度都在正常范围之内
题目三:
作业三 7-2
用户输入一组选项和数据,进行与直线有关的计算。选项包括:
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",
输出格式:
见题目描述。
代码如下:
import java.util.Scanner; public class Main { public static void main(String[] args) { int num; Scanner input=new Scanner(System.in); Format P=new Format(); P.s=input.nextLine(); if(!P.matche()) { System.out.println("Wrong Format"); return; } if(P.numberNo()==1) { if(P.numberPoints()==2) { line c=new line(); c.a=P.getPoints(1); c.b=P.getPoints(2); if(c.a.coincide(c.b)) { System.out.println("points coincide"); return; } if(c.isK()) System.out.println(c.getK()); else System.out.println("Slope does not exist"); } else { System.out.println("wrong number of points"); return; } } else if(P.numberNo()==2) { if(P.numberPoints()==3) { points c=new points(); c=P.getPoints(1); line d=new line(); d.a=P.getPoints(2); d.b=P.getPoints(3); if(d.a.coincide(d.b)) { System.out.println("points coincide"); return; } if(d.isK()) System.out.println(d.getDistance(c)); else System.out.println(Math.abs(d.a.x-c.x)); } else { System.out.println("wrong number of points"); return; } } else if(P.numberNo()==3) { if(P.numberPoints()==3) { points c=new points(); c=P.getPoints(1); line d=new line(); d.a=P.getPoints(2); d.b=P.getPoints(3); if(d.a.coincide(d.b)) { System.out.println("points coincide"); return; } System.out.println(d.isOnline(c)); } else { System.out.println("wrong number of points"); return; } } else if(P.numberNo()==4) { if(P.numberPoints()==4) { line c=new line(); line d=new line(); c.a=P.getPoints(1); c.b=P.getPoints(2); d.a=P.getPoints(3); d.b=P.getPoints(4); if(c.a.coincide(c.b)||d.a.coincide(d.b)) { System.out.println("points coincide"); return; } System.out.println(d.isParallel(c)); } else { System.out.println("wrong number of points"); return; } } else if(P.numberNo()==5) { if(P.numberPoints()==4) { line c=new line(); line d=new line(); c.a=P.getPoints(1); c.b=P.getPoints(2); d.a=P.getPoints(3); d.b=P.getPoints(4); if(c.a.coincide(c.b)||d.a.coincide(d.b)) { System.out.println("points coincide"); return; } if(!c.isParallel(d)) c.getIntersection(d); else System.out.println("is parallel lines,have no intersection point"); } else { System.out.println("wrong number of points"); return; } } else System.out.println("wrong number of points"); } } class line { points a,b; public boolean isK() { if(this.a.x==this.b.x) return false; else return true; } public double getK() { return (this.b.y-this.a.y)/(this.b.x-this.a.x); } public double getB() { return this.a.y-this.a.x*this.getK(); } public double getDistance(points a) { double numerator=Math.abs(getK()*a.x-a.y+this.getB()); double denominator=Math.sqrt(1+Math.pow(this.getK(),2)); return numerator/denominator; } public boolean isOnline(points a) { if((a.y-this.a.y)*(this.b.x-this.a.x)-(this.b.y-this.a.y)*(a.x-this.a.x)==0) return true; else return false; } public double getA1() { return this.b.y-this.a.y; } public double getB1() { return this.a.x-this.b.x; } public double getC1() { return this.a.x*this.getA1()+this.a.y*this.getB1(); } public void getIntersection(line a) { double A,B; double A1,B1,C1; double A2,B2,C2; A1=a.getA1(); B1=a.getB1(); C1=a.getC1(); A2=this.getA1(); B2=this.getB1(); C2=this.getC1(); double X,Y; A=(B2*C1-B1*C2)/(A1*B2-A2*B1); B=(A1*C2-A2*C1)/(A1*B2-A2*B1); System.out.print(A+","+B+" "); points d=new points(); d.x=A; d.y=B; if(A==this.a.x&&B==this.a.y||A==this.b.x&&B==this.b.y||A==a.a.x&&B==a.a.y||A==a.b.x&&B==a.b.y) { System.out.print("false"); return ; } System.out.print(this.isBetween(d)||a.isBetween(d)); } public boolean isParallel(line a) { if(this.getA1()*a.getB1()==this.getB1()*a.getA1()) return true; else return false; } public boolean isBetween(points a) { if(a.x>=Math.min(this.a.x,this.b.x)&&a.x<=Math.max(this.a.x,this.b.x)&&a.y>=Math.min(this.a.y,this.b.y)&&a.y<=Math.max(this.a.y,this.b.y)) return true; else return false; } } class Format { String s; public boolean matche() { String regx1="(([+|-]?[1-9]+([\\.][0-9]+|[0-9]*)|([+|-]?[0]([\\.][0-9])?))[,]([+|-]?[1-9]+([\\.][0-9]+|[0-9]*)|([+|-]?[0]([\\.][0-9])?)))"; if(this.s.charAt(0)>'5'||this.s.charAt(0)<'1') return false; if(this.s.charAt(1)!=':') return false; String arr=this.s.substring(2); String arr1[]=arr.split(" "); for(int i=0;i<arr1.length;i++) { if(!arr1[i].matches(regx1)) return false; } return true; } public int numberNo() { return Integer.parseInt(this.s.split(":")[0]) ; } public int numberPoints() { String arr[]=this.s.split(" |:"); return (arr.length-1); } public boolean numberFormat(int No) { switch(No){ case 1 : if(this.numberPoints()==2) return true; case 2 : if(this.numberPoints()==3) return true; case 3 : if(this.numberPoints()==3) return true; case 4 : if(this.numberPoints()==4) return true; case 5 : if(this.numberPoints()==4) return true; default: return false; } } public points getPoints(int index) { points a=new points(); String arr[]=this.s.split(":")[1].split(" "); a.x=Double.parseDouble(arr[index-1].split(",")[0]); a.y=Double.parseDouble(arr[index-1].split(",")[1]); return a; } } class points { double x,y; public double juli(points a) { return Math.sqrt(Math.pow(this.x-a.x,2)+Math.pow(this.y-a.y,2)); } public boolean coincide(points a) { if(this.x==a.x&&this.y==a.y) return true; else return false; } }



由于此次大作业是我首次使用面向对象的思考方法来进行的,本来是很简单的问题在我刚开始编写时思路却一直很乱导致写出的代码最后圈复杂度以及代码深度较高,还有很高的提升空间
题目四:
用户输入一组选项和数据,进行与三角形有关的计算。选项包括:
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"


本次大作业是我最近以来写过的最复杂的题目,难度和复杂度都远超前两个题,虽然将题目分为线,点,三角形,格式类,但是由于对类的理解还不够深刻,导致主类过于复杂,以及其他类的圈复杂度,以及代码深度较为不理想,方法相似度高,尤其是在三角形类当中,计算线与三角形交点个数和得到线与三角形的交点的方法中,不仅执行的操作几乎一样,而且同样多次使用if else语句,圈复杂度达到了29,虽然代码可以通过,但是依旧有许多进步空间
三.踩坑心得
题目一:
这道题目在一开始写的时候并没有对题目进行仔细的分析,在提交代码之后总会出现一些莫名其妙的错误,虽然题目的逻辑很清晰,但是在细节上会出现很多问题,特别是在判断奇偶校验位或结束位是否正确时,例如在判断奇偶检验位的时候,首先是要判断是否存在奇偶校验位,然后才判断是否校验正确,我当时就是没有考虑到这种情况,导致一直存在过不去的点.还有要一开始就要判断格式输入是否正确,若一开始输入的字符串就少于11位,肯定也是不可以的.
题目二:
这一道题目只有一道非常大的坑,并且这一道坑延续在了后面很多道题目,这就是正则表达式判断输入是否符合格式,
public static boolean matches(String arr) { String regx="([+-]?[1-9][0-9]*\\.[0-9]+)|([+-]?0\\.[0-9]+)|([+-]?[1-9][0-9]*)|(0)"; if(arr.matches(regx)) return true; else return false; }
本道题目使用这个正则表达式是可以通过所有的格式错误的点的,但是到下一道题就不行了
题目三:
这道题目在格式错误上面花费我很多的时间,我本以为使用第一道题目的正则表达式就可以通过,事实上确实是通过了所有的格式错误点,但是下面的测试点就是存在几个死活都过不去,我改变其他算法也尝试过,结果都是一样的.然后我开始把问题望向了格式,会不会是我的格式要求太严格,把测试点中本应该可以通过的数据当成了错误的格式.对此问题,我把判断格式的语句注释掉,果不其然,下面过不去的测试点全部通过,.虽然这个过程我呈现出的只有仅仅这句话,但是我是实实在在经历了两天疯狂找bug的过程,谁曾想问题竟然出自这么一个地方.这道题目还有不少坑,比如判断平行需要首先判断斜率是否存在,斜率不存在的线如何求交点等等,但是我觉得都不如我最开始遇到的难以解决
String regx="([+-]?[1-9][0-9]*\\.[0-9]+)|([+-]?0\\.[0-9]+)|([+-]?[1-9][0-9]*)|(0)",//出错
String regx1="(([+|-]?[1-9]+([\\.][0-9]+|[0-9]*)|([+|-]?[0]([\\.][0-9])?))[,]([+|-]?[1-9]+([\\.][0-9]+|[0-9]*)|([+|-]?[0]([\\.][0-9])?)))";//通过
题目四:
判断三角形类型,需要用到线的长度,double类型运算本来就有误差,我在算长度的时候又开了平方,导致误差很大,明明输入的是直角三角形3,4,5,在计算完边长后变成了3,4,5.00000000008,解决方法也很简单,再多写一个方法,返回边长的平方,这样误差就很小了,其实最好的方法还是在判断三角形时a^2+b^2-c^2<1e-6,不使用=,就能忽略误差.本题还有一个大坑,在选项2中输出格式有要求:输出的数据若小数点后超过6位,只保留小数点后6位,多余部分采用四舍五入规则进到最低位。小数点后若不足6位,按原始位数显示,不必补齐。例如:1/3的结果按格式输出为 0.333333,1.0按格式输出为1.0.当时写的时候确实难到了我,不过我还是用到了最直接的办法,判断输出的数值乘上1e6,在判断个位数是否为0,这样虽然不能百分之百确定是否该数为6位小数,但是通过了所有的测试点.这道题目中最难的我认为就是选项四了,因为线与三角形的交点个数情况很多,我也尝试了很多的办法来计算面积,但是都不尽人意,最终我先计算交点个数,然后通过交点个数来求交点,然后判断交点的位置.这三步在我现在看来确实是很蠢的三步,尤其是计算交点个数,然后求交点这两个方法明明可以放在一起来写,我还是把他俩分开,两个方法的内容及其相似,给代码的运行添加了不必要的负担
public int intersetionNum(line l) { int count=0; line A=new line(); line B=new line(); line C=new line(); A.a=this.b; A.b=this.c; B.a=this.c; B.b=this.a; C.a=this.b; C.b=this.a; if(!A.isParallel(l)) { points a=new points(); a=A.getIntersection(l); if(A.isBetween(a)) count++; } if(!B.isParallel(l)) { points a=new points(); a=B.getIntersection(l); if(B.isBetween(a)) count++; } if(!C.isParallel(l)) { points a=new points(); a=C.getIntersection(l); if(C.isBetween(a)) count++; } return count; }
public points[] getIntersection(line a) { int count=0; line A=new line(); line B=new line(); line C=new line(); A.a=this.b; A.b=this.c; B.a=this.c; B.b=this.a; C.a=this.b; C.b=this.a; if(this.intersetionNum(a)==2) { points []inter=new points[2]; if(!A.isParallel(a)) { points p=new points(); p=A.getIntersection(a); if(A.isBetween(p)) { inter[count]=p; count++; } } if(!B.isParallel(a)) { points p=new points(); p=B.getIntersection(a); if(B.isBetween(p)) { inter[count]=p; count++; } } if(!C.isParallel(a)) { points p=new points(); p=C.getIntersection(a); if(C.isBetween(p)) { inter[count]=p; count++; } } return inter; } else if(this.intersetionNum(a)==3) { points []inter=new points[3]; if(!A.isParallel(a)) { points p=new points(); p=A.getIntersection(a); if(A.isBetween(p)) { inter[count]=p; count++; } } if(!B.isParallel(a)) { points p=new points(); p=B.getIntersection(a); if(B.isBetween(p)) { inter[count]=p; count++; } } if(!C.isParallel(a)) { points p=new points(); p=C.getIntersection(a); if(C.isBetween(p)) { inter[count]=p; count++; } } return inter; } else { points []inter=new points[0]; return inter; } }
选项五的逻辑并不复杂,但我也在一个地方吃到了亏,我的思路是通过一个点向左方射线看与三角形交点的个数

在这种情况下D向左作射线

会与AB有交点,但是D是在三角形外所以是我忘记了射线与三角形的交点也应该在三角形上面才可以
四.改进建议
作业三7-1计算两点之间的距离,在当时的题目上没有按照类来写,导致后面的两次作业需要用到点类的时候很麻烦,不得不又重新写了一遍第一题,真的深刻的理解了面向对象的好处.
作业三7-3的计算三角形被线切割后的面积的方法,写的及其难以阅读,及其逻辑混乱,在提交之后就一直想着改进,精简一下代码,将计算交点个数和得到交点合并一起,在得到交点的时候还能记录下交点所在边线,这样也不需要在之后找点位于哪一条线,这样代码既简单又容易阅读
五.总结
这三次题目集让我见识到为什么有些代码可以写这么多行,,确实是对于Java面向对象的编程方法有了很深刻的了解,在写三角形问题时,可以直接调用前面题目写的方法,确实是很方便,但是如此的同时,对我们类,方法的编写又有了很高的要求,还需要在之后的学习中不断进步,吸收知识

浙公网安备 33010602011771号