PTA前第三次作业总结

(一)前言:

      题目集一:(九道题目难度较低,主要是进行简单的输入输出)

    • 7-1:身体质量指数(BMI)测算

        难度:1

        知识点:采用多重if语句分支结构解决简单的输入输出

      7-2: 长度质量计量单位换算

        难度:2

        知识点:采用单精度浮点数,将计算的数据强制转换成float类型

      7-3: 奇数求和

        难度:1

        知识点:数组的创建声明以及使用

      7-4:房产税费计算

        难度:3

        知识点:多重if语句分支结构、数据强制转换成float类型

      7-5:游戏角色选择

        难度:2

        知识点:多重if语句分支结构完成一系列输出

      7-6:学号识别

        难度:4

        知识点: 字符串长度的判断、获取字符串的某个字符、if语句中多个表达式的处理

      7-7:判断三角形类型

        难度:4

        知识点:组成三角形的条件、多重if语句判断等腰三角形、等腰直角三角形、等边三角形以及一般三角形

      7-8:巴比伦法求平方根近似值

        难度:3

        知识点:数据强制转换成float类型、计算得出的估计值满足精确度

      7-9:二进制数值提取

        难度:4

        知识点:字符串长度的判断、获取字符串的某个字符、在输出前设计检查有无结束符的代码

    • 题目集二(三道题目相比前一次作业难度增加了一些,需要熟练掌握字符相关知识)

      7-1:字母-数字转换

        难度:3

        知识点:字符串长度的判断、获取字符串的某个字符、将字符串的每个字符转换为数字存入整型数组中(大写字母A-Z所对应的ASCII码值为65-90,小写字母a-z所对应的ASCII码值为97-122)

      7-2: 串口字符解析

        难度:5

        知识点:获取字符串的某个字符、过滤掉空闲、起始、结束以及奇偶校验位之后的数据、判断结束符和奇偶校验是否合格

      7-3: String的格式判断与内容提取

        难度:3

        知识点:获取字符串的某个字符、if语句中多个表达式的处理、采用字符串的substring用法获取其中一段字符串

      •  题目集三(难度大大增加,根据要求最好是创建多个类,保证代码条理清晰,各个方法各司其职)

      7-1:点线形系列1-计算两点之间的距离

        难度:6

        知识点:通过正则表达式判断输入是否格式正确、采用字符串的split用法将坐标的逗号去除并将每个坐标的x、y数据保存在数组中、采用Double.parseDouble()函数将字符转化成double类型

      7-2:点线形系列2-线的计算

        难度:8

        知识点:通过正则表达式判断输入是否格式正确、通过Arraylist用法获取动态大小的数组、采用字符串的split用法将坐标的逗号去除并将每个坐标的x、y数据保存在数组中、创建Point以及Line的类以方便使用各种点和线的计算、各种类中数据的封装及方法的使用、计算直线斜率、点到直线的距离、三点是否共线、两线是否相交及交点所处位置的判断

      7-3:点线形系列3-三角形的计算

        难度:10

        知识点:通过正则表达式判断输入是否格式正确、通过Arraylist用法获取动态大小的数组、字符串的split用法、创建Point、Line、Side的类以方便使用各种点、线、面的计算、各种类中数据的封装及方法的使用、判断是否为等腰、等边、钝角、直角、锐角三角形、根据数据是否为有限小数来控制输出格式、计算直线切割三角形得到的两部分图形的面积、采用射线法判断点是否处于三角形内部

      (二)、设计与分析

      题目集一-7-9分析

      此题需要我们设计代码,将一个由-1为结束符的字符串去掉非0和1的字符以及结束符的数据内容进行输出。

      一开始我的想法是在循环中判断字符是否为0或1,不是则判断下一个,直到发现-1则跳出循环,但却忽略了很重要的一点,即对字符是否含有结束符的判断。

      所以这里别有构思的一点是:先设计一个for循环来检测输入的字符串是否含有结束符-1,如果有结束符再进行下一步的判断。

      复制代码
      for( i=0; i<str.length();i++){
                  if(str.charAt(i)=='-'&&str.charAt(i+1)=='1')
                          break;
                  if(i==str.length()-1)
                      t=0;
              }
              if(t==0)
                  System.out.println("Wrong Format");
              else
              {
                  for( i=0; i<str.length();i++)
                  {
                      if(str.charAt(i)!='0'&&str.charAt(i)!='1')
                          {}
                      else
                          System.out.print(str.charAt(i));
                      if(str.charAt(i)=='-'&&str.charAt(i+1)=='1')
                          break;
                  }
              }
      复制代码
    • 题目集二-7-2分析
    • 由于题目集二-7-2未设计多个类,由图2可知,此段代码冗长繁杂,为错误典范,设计思路与C语言无异
      复制代码
              Scanner input = new Scanner(System.in);
              String s = input.nextLine();
              String s1 =s;
              int i=0,j=0, n=0, a=0, b=0;
              int x = 1;
              for(i=0;i<s.length();i++)
              if(s.charAt(i)==0||s.charAt(i)==0) 
                  {}
              else if(i==s.length())
                  System.out.println("Wrong Format");
              if(s.length()<11)
                  System.out.println("null data");
              else {
                  for(i=0;i<s.length();i++)
                      if(s.charAt(i)=='0')
                          x=0;
                      if(x==1)
                          System.out.println("null data");
              
              for( j=0; s.length()-b>=11;j++) {
                  for(i = b; i<s.length()-b; i++){
                      if(s.charAt(i)=='1'&&s.charAt(i+1)=='0')
                      {
                          a = i+2;
                          break;
                      }
                  }
                  if(i==s.length())
                      System.out.println("null data");
                  for(i = a; i<s.length()-b; i++) {
                      if(s.charAt(a+8)=='1'&&s.charAt(i+9)=='1'){
                          b = a+7;
                          n++;
                          break;
                      }
                      else     
                          n=0;
                  }
                  
                  if(b == a+7) { 
                      s1 = s.substring(a,b+1);
                      System.out.println(n+":"+s1);
                      break;
                  }
                  if(n==0){
                      if(s.charAt(a+8)!='1')
                          System.out.println(n+"parity check error");
                      else
                          System.out.println(n+"validate error");
      
                  }
      
              }
          
      复制代码

       

       

       

       

       ·题目集三-7-1分析

      • 从这道题开始,我学习到了正则表达式的基本用法。

      • 这段代码我用来检测是否满足坐标x,y的格式,
      • 其中表示带符号的浮点数:   
        • [+-]?  表示正负号可省略
        • \d*   表示一位或多位的数字

        • (.\d*)? 表示小数点加上几位数字可省略

        • 然后在\符号后再添加转义符\进行转义即可写入代码

        • !注意!此代码需要添加这两个包的用法

          • import java.util.regex.Matcher;
            import java.util.regex.Pattern;

            !注意!m.matches()的返回类型,即此函数返回类型为boolean

            复制代码
                static boolean Test(String string) {
                        String str = string;
                        String pattern = "[+-]?\\d*(.\\d*)?,[+-]?\\d*(.\\d*)?";
            
                        Pattern r = Pattern.compile(pattern);
                        Matcher m = r.matcher(str);
                        return m.matches();
                    }
            复制代码

            我设计的是运用split()先将字符串z中的空格去除掉,保存在s字符串数组中,设置string字符串将原字符串分解成的小段字符串赋给他,在循环中依次判断是否符合坐标格式,如果符合,再运用split()继续将每个小字符串中的逗号去除掉,再强制转换数据类型分别保存在double数组x[]和y[]中,然后以小字符串的个数i来判断输入了几对格式正确的坐标

            复制代码
                   double x1, x2, y1, y2;
                    int i = 0;
                    double [] x = new double [100];
                    double [] y = new double [100];
                    String z = input.nextLine();
                    String [] s = z.split(" ");
                        while(i<s.length) {
                            String string =s[i];
                        if(Test(string)) {//每一个点坐标是否格式正确
                            String [] num = s[i].split(",");
                            x[i] = Double.parseDouble(num[0]);
                            y[i] = Double.parseDouble(num[1]);
                            i++;
                        }
                        else {
                            System.out.println("Wrong Format");
                            break;
                        }
                        if(i==3) {    
                            System.out.println("wrong number of points");
                            break;
                        }
                    }
                    if(i==2)
                        System.out.println(CalDistance(x[0],y[0],x[1],y[1]));
                
            复制代码

             

             

            题目集三-7-2分析:

            设置point点类,储存点坐标的x和y值,在主类的Caldistance函数中计算两点间的距离,将点作为参数传入函数使代码更简洁

            设置line点类,储存线的一些信息如直线的斜率、在y轴的截距,将点传入方法计算出k和by

            这一题在上一题的基础上进行了改进,这一段略微复杂的正则表达式就直接判断出来多个坐标的形式

             

            [1-5]\\d*:([+-]?\\d*(.\\d*),[+-]?\\d*(.\\d*) )+[+-]?\\d*(.\\d*),[+-]?\\d*(.\\d*)
            这里思维活跃了一些,想到可以直接把坐标符合的形式加个空格用括号括起来,再写一个+表示可以多个坐标加空格,再最后补上没有空格的坐标形式

             

            复制代码
                static boolean Test(String string) {//检测输入是否格式正确
                        String str = string;
                        String pattern = "[1-5]\\d*:([+-]?\\d*(.\\d*),[+-]?\\d*(.\\d*) )+[+-]?\\d*(.\\d*),[+-]?\\d*(.\\d*)";
                        Pattern r = Pattern.compile(pattern);
                        Matcher m = r.matcher(str);
                        return m.matches();
                    }

            复制代码

            这道题我只考虑了计算直线的斜率和截距,其他的一些方法都还是放在了主类当中,构思还是不是很严谨有序;

            主要是因为功夫太浅啊,做题考虑不周就容易缝缝补补涂涂改改,想法思路不清晰,或者是想多放一些代码到子类中却受到各种障碍,所以不得不把代码加到主类之中,导致了冗长繁杂的毛病。

            在这道题中,特别要注意的是直线的斜率!

            如果之曲线斜率不存在,则函数不能返回正常值,所以要另外提出来分情况讨论;

            例如下面这一段代码,作用是分析四点构成的两条直线的交点位置,以及判断是否处在两条线段上;

            首先排除两直线都垂直于x轴的情况,因为不产生交点;

            其次分别是前两点所构成的直线垂直于x轴、后两点所构成的直线垂直于x轴;

            然后是正常情况,先根据斜率判断是否有交点,再判断两直线的交点位置;

             

            复制代码
                      if(n==5)
                                        if(x.size()==8)
                                        {
                                            if(a.x==b.x&&c.x==d.x)
                                                System.out.println("is parallel lines,have no intersection point");
                                               else if (a.x==b.x) {
                                                    
                                                        l34.k=l34.Calk(c,d);
                                                        l34.by=l34.Calby(c,d);
                                                        Point p0 = new Point();
                                                        p0.x=a.x;
                                                        p0.y=l34.k*a.x+l34.by;
                                                        System.out.println(p0.x+","+p0.y+judge(a,b,c,d,p0));
                                                    }
                                                else if(c.x==d.x) {
                                                        
                                                        l12.k=l12.Calk(a,b);
                                                        l12.by=l12.Calby(a,b);
                                                        Point p0 = new Point();
                                                        p0.x=c.x;
                                                        p0.y=l12.k*c.x+l12.by;
                                                        System.out.println(p0.x+","+p0.y+judge(a,b,c,d,p0));
                                                    
                                                    }
                                    
                                                else {
                                                l12.by=l12.Calby(a,b);
                                                l34.by=l34.Calby(c,d);
                                                l12.k=l12.Calk(a,b);
                                                l34.k=l34.Calk(c,d);
                                            
                                                Point p = new Point();
                                                p.x=jiaodianx(l12,l34);
                                                p.y=jiaodiany(jiaodianx(l12,l34),l12.k,l12.by);
                                                
                                                if(l12.k==l34.k)
                                                    System.out.println("is parallel lines,have no intersection point");
                                                else
                                                    System.out.println(p.x+","+p.y+" "+judge(a,b,c,d,p));
                                            }
                                        }
            复制代码

             

             

             

            题目集三7-3分析:

            这道题延续了第二题判断输入的方法,通过ArrayList可控数组大小来决定被赋值的点的数量

            !注意加上ArrayList包:

            import java.util.ArrayList;

            此段代码是给各个点的xy赋值,以及判断是否有重复的点存在;

            也是这里是导致我的主类占据了很多行数,这是需要改进的地方;

            在这里我有学习到一个新知识(其实很基础哈哈哈自惭形愧了);

            就是跳出多重循环只需要在大循环前面加上一个out:然后break out;就能跳出大循环了!

             

            复制代码
                    
                    ArrayList <Double> x = new ArrayList<Double>(); 
                    String string= input.nextLine();    
                        if(Test(string)) {//是否格式正确
                            String [] num = string.split(":|,| ");
                             n = Integer.parseInt(num[0]);
                            for(i=0; i<num.length-1; i++)
                            x.add (Double.parseDouble(num[i+1])) ;
                        }
                        else 
                            System.out.println("Wrong Format");
                        if(x.size()>8) 
                            System.out.println("wrong number of points");
                        
                        else {
                            switch(x.size()) {
                            
                                case 6: a.x = x.get(0); 
                                    a.y = x.get(1);
                                    b.x = x.get(2); 
                                    b.y = x.get(3);
                                    c.x = x.get(4); 
                                    c.y = x.get(5);
                                    break;
                                case 8: a.x = x.get(0); 
                                    a.y = x.get(1);
                                    b.x = x.get(2);
                                    b.y = x.get(3);
                                    c.x = x.get(4);
                                    c.y = x.get(5);
                                    d.x = x.get(6);
                                    d.y = x.get(7);
                                    break;
                                case 10: a.x = x.get(0); 
                                    a.y = x.get(1);
                                    b.x = x.get(2);
                                    b.y = x.get(3);
                                    c.x = x.get(4);
                                    c.y = x.get(5);
                                    d.x = x.get(6);
                                    d.y = x.get(7);
                                    e.x = x.get(8);
                                    e.y = x.get(8);
                                    break;
                                    
                                    
                        }
                            out:
                                            for(i=0;i<x.size()-3;i=i+2)
                                                for(j=i+2;j<x.size()-1;j=j+2)
                                                    if(x.get(i)==x.get(j)&&x.get(i+1)==x.get(j+1))
                                                    {
                                                        repeat=1;
                                                        break out;
                                                    }
            复制代码

             

            这道题在相比于前一题,增加了面的角度,即side这一个类;

            我考虑的很多函数其实并不是写在side里面,只是在side类里写了cos方法,用来计算三角形的某个角的余弦值,再以此另外设置函数判断三角形是否为钝角、直角、锐角三角形

             

             下面是三个类:

            复制代码
            class Side{
                    double cos;
                    double cos(double a,double b,double c) {
                        this.cos = (double)(a*a+b*b-c*c)/(2*a*b);
                        return this.cos;
                    }
                    boolean pointline(Point a,Point b,Point c) {
                        Line l12 = new Line();
                        Line l13 = new Line();
                        
                        l13.Calk(a, c);
                        l12.Calk(a, b);
                        
                        if((a.x<b.x&&a.x>c.x&&a.y<b.y&&a.y>c.y&&l12.k==l13.k)
                                ||(a.x<c.x&&a.x>b.x&&a.y<c.y&&a.y>c.y&&l12.k==l13.k))
                            return true;
                        else
                            return false;
                    }
                }
                
                class Point{
                    double x;
                    double y;
                
                }
                
                class Line{
                    
            
                    double k;//两点构成的直线的斜率
                    
                    double by;//直线在y轴的截距
                    double d;//两点之间的距离
                    public double Calk(Point a,Point b) {
                        k = (double)((a.y-b.y)/(a.x-b.x));
                        return k;     
                    }    
                    
                    public static double Caldistance(Point a,Point b) {
                        return  (double)(Math.sqrt(Math.pow(a.x-b.x,2)+Math.pow(a.y-b.y,2)));
                        
                    }
                    
                    
                    public double Calby(Point a,Point b) {
                        by = (double)(a.y-a.x*k);
                        return by;
                    }
                    
                }
            复制代码

             

             

             

             下面是判断角度的方法:

             

            复制代码
                static void angle(Point a,Point b,Point c) {
                    Line l12 = new Line();
                    Line l23 = new Line();
                    Line l13 = new Line();
                    l12.d=Line.Caldistance(a,b);
                    l12.d=Line.Caldistance(c,b);
                    l12.d=Line.Caldistance(a,c);
                    Side triangle = new Side();
                    boolean judge1 = false;
                    boolean judge2 = false;
                    boolean judge3 = false;
                    if(triangle.cos(l12.d, l23.d, l13.d)<0
                            || triangle.cos(l23.d, l13.d, l12.d)<0
                            || triangle.cos(l12.d, l13.d, l23.d)<0)
                    {
                        judge1=true;
                        judge2=false;
                        judge3=false;
                    }
                    else if(triangle.cos(l12.d, l23.d, l13.d)==0
                            || triangle.cos(l23.d, l13.d, l12.d)==0
                            || triangle.cos(l12.d, l13.d, l23.d)==0)
                        {
                            judge1=false;
                            judge2=true;
                            judge3=false;
                        }
                    else if(triangle.cos(l12.d, l23.d, l13.d)>0
                            || triangle.cos(l23.d, l13.d, l12.d)>0
                            || triangle.cos(l12.d, l13.d, l23.d)>0)
                        {
                            judge1=false;
                            judge2=true;
                            judge3=false;
                        }
                    
                    System.out.print(judge1+" "+judge2+" "+judge3);
                }
                static void linewithside(Point a,Point b,Point c,Point d,Point e) {
                    Line l12 = new Line();
                    
                    Line l34 = new Line();
                    Line l45 = new Line();
                    Line l35 = new Line();
                    l12.Calk( a, b );
                    l34.Calk( c, d );
                    l45.Calk( d, e );
                    l35.Calk( c, e );
                    if(l12.k==l34.k||l12.k==l45.k||l12.k==l35.k)
                        System.out.println("The point is on the edge of the triangle");
                }
                static void pointwithside(Point a,Point b,Point c,Point d) {
                    
                    Side tt = new Side();
                    if(tt.pointline(a,b,c)==true
                            ||tt.pointline(a,c,d)==true
                            ||tt.pointline(a,d,b)==true)
                        System.out.println("on the triangle");
                }
            复制代码

             

             (三)踩坑心得

             1.没有注意 double和float的数据类型,虽然说都是表示浮点数,之前一直以为只是精度不同占据内存空间不同而已,没想到小数默认是double类型,用floa需要进行强制转换;

             2.字符串的substring用法没有记清楚,s.substring(a,b)的返回值是截取的字符串s从a到b-1这一部分,而非包括s.charAt(b);

             3.在做题过程中根据next()与nextLine()的区别,以为自作聪明可以用循环内的next()来获取每一个以空格结尾的坐标,却没有考虑到如果输入的以空格结尾的字符串根本不符合坐标格式,就不能跳过来识别下一个字符串了;

             4.运行结果输出了NaN这个不明所以的东西,一开始还以为是我手滑不小心打的字母,经过一步步debug还是百思不得其解,它为什么就给我输出这个鬼东西,在搜集一些资料才发现是得出的结果就是有问题的,NaN表示Not a Number,就是说可能出现了数据极其小或者极其大或者无法运算的情况,最后才发现是我没考虑到之前斜率不存在的情况;

             5:没有根据数据是否为有限小数来控制输出格式,也不知道怎么判断一个数是否为有限小数,在请教几位同学之后才知道,其实可以转化成(x*1000000%10)是否等于0的问题。

             (四)改进建议

             1.多考虑主类和子类的关系,处理好各种调用,思路和表达都要清晰有条理,代码才能看得舒心,用的放心。

             2.注意double精度问题,时刻考虑将运算结果强制转化成float类型,否则数据不准确。

             3.可以多学习一些处理点线面的数据更为方便的数学技巧,能避免很多问题,实质性内容更明显。

             4.多去找问题发现问题,反思总结前面代码是否合适,加强自己面对挫折的勇气和敢于尝试的信念,不能惧怕任何推翻重来的可能。 

             5.多查找资料多请教同学,掌握的越多,大脑储备更全,以应对解决任何未知问题。

            (五)总结

            这次实验计我学习到了很多,也发现了自己的很多问题,以及认识到了一些基础知识的缺乏。认识问题不够透彻,靠主观臆断试错,而不是先查询资料搞清楚.通过此次实验,我深刻认识到Java基本知识的重要性,并且学习到很多有用的知识,还锻炼了更加仔细探究问题的能力。在调试过程中,我发现有很多不懂的地方,绞尽脑汁也不清楚自己问题出现在哪,只能查找相关资料一步一步慢慢学习新知识,并将旧知识加以巩固。认识到我的各种不足后,我也会更加细致,多学习,多积累,遇到不懂的多借助网上资源进行自学。此外,在学习方法方面,我认识到应该提前清晰地计划好要解决的部分,不能将许多bug堆在一起等着之后再一个一个解决,否则会酿成不可预料无法挽救的可怜局面。总之,学习编程要时刻保持严谨的学术态度,细致认真脚踏实地才能有所建树。

posted @ 2022-10-01 20:48  cxgfxcsv  阅读(109)  评论(0)    收藏  举报