对前三次题目集的总结及分析

一. 前言

​ 首先,总结一下这三次题目集的我的个人感受及做题情况。从题量上看,三次题目集的题量是慢慢减少的;从题目质量和难度上看,这三次题目集难度和质量是逐渐加高的,由简单的函数操作到类的设计与实现;从知识点看,第一次题目集考察的主要是一些基本语法,例如选择循环语句,代数计算,逻辑判断等;第二次题目集考察的主要是一些JAVA中重要的类的基本使用(如String),数组的基本使用以及构造函数需要考虑健壮性以及代码的简洁;第三次题目集考察的主要是类的基本使用以及考虑其封装性,数组(如ArrayList,LinkList)的使用以及设计出的程序的健壮性。从我个人感受谈,这三次题目集循序渐进,让我逐渐从面向过程过渡到面向对象,也为后面面向对象设计打下一定的基础。

二. 设计与分析

根据我的做题情况以及做相应题目所花费时间和精力,我重点对以下题目进行分析

  • 题目集1中的7-8

    题目内容为输入三角形的三条边,判断三角形的类型;以下是我的源码:

package firstpta;

/**
 * @author:everglow
 * @data 2021/9/9 22:25
 */
import java.util.Scanner;
public class eight {
    public static void main(String[] args){
        Scanner input=new Scanner(System.in);
        float a= input.nextFloat();
        float b=input.nextFloat();
        float c=input.nextFloat();
        if(a<1||a>200||b<1||b>200||c<1||c>200){
            System.out.print("Wrong Format");
        }
        else if(a+b<=c||a+c<=b||b+c<=a){
            System.out.print("Not a triangle");
        }
        else if(a==b&&b==c&&a==c){
            System.out.print("Equilateral triangle");
        }
        else if((a*a+b*b-c*c<0.1&&a==b)||(b*b+c*c==a*a&&b==c)||(a*a+c*c==b*b&&a==c)){
                System.out.print("Isosceles right-angled triangle");
        }
        else if(a*a+b*b==c*c||a*a+c*c==b*b||b*b+c*c==a*a){
                System.out.print("Right-angled triangle");
        }
        else if(a==b||b==c||a==c){
            System.out.print("Isosceles triangle");
        }
        else{
            System.out.print("General triangle");
        }
    }
}
度量:(方法和类)
Method CogC ev(G) iv(G) v(G)
firstpta.eight.main(String[]) 16 1 7 25
Class OCavg OCmax WMC
firstpta.eight 7 7 7
UML类图:

设计和分析:

​ 这题考察的输入三角形的长宽高,判断三角形的类型。我的思路是利用选择语句嵌套完成需求,整体完成下来还算顺利,因为主要考验的还是你使用基本语法的熟练程度,在提交调试的时候一直遇到一个等腰直角三角形的测试点过不去,后来经过查阅资料发现是直角三角形的判断条件不能是a2+b2=c2而应该是c2-a2-b2<0.1(后面数值0.1可以改小但是得大于0),原因是float类型在存储值时不一定完全等于你输入的值,double类型的位数比较多,所以精度有所不一样,判断方式也要因此而改变。

​ 分析7-8的度量,类的圈复杂度是7,应该算是正常情况,毕竟此题需要的选择条件语句较多,第一次题目集的代码还比较简单,不怎么设计类的设计,所以类的UML图也是简单明了。

  • 题目集2中的7-4和7-5

    ​ 这俩题题目类似,所以我把俩个题目一起拿出来分析,7-4的题目内容是给定一个日期,求下一天;

    7-5的题目内容是给定一个日期和N,求前N天;以下是我俩题的源码:

    7-4

    import java.util.Scanner;
    
    /**
     * @author:everglow
     * @data 2021/9/21 18:26
     */
    
    public class fourth{
            int year;
            int month;
            int day;
            public static void main(String[] args){
                Scanner input=new Scanner(System.in);
                Main data=new Main();
                data.year=input.nextInt();
                data.month=input.nextInt();
                data.day=input.nextInt();
                if(checkInputValidity(data.year,data.month,data.day)==false){
                    System.out.print("Wrong Format");
                }
                else {
                    System.out.print("Next date is:");
                    nextDate(data.year, data.month, data.day);
                }
            }
    
            public static boolean isLeapYear(int year){     //判断是否闰年
                boolean p=false;
                if((year%4==0&&year%100!=0)||year%400==0){
                    p=true;
                }
                return p;
            }
    
            public static boolean checkInputValidity(int year,int month,int day){
                boolean x=true;
                if(!(year>=1820&&year<=2020)||!(month>=1&&month<=12)||!(day>=1&&day<=31)
                        ||(!isLeapYear(year)&&(month==2)&&(day>=29))){
                    x=false;
                }
                return x;
            }
            public static void nextDate(int year,int month,int day){
                int[] monthnum=new int[]{31,28,31,30,31,30,31,31,30,31,30,31};
                if(isLeapYear(year)){
                    monthnum[1]=29;
                }
                if(day<monthnum[month-1]){
                    day=day+1;
                }
                else if(month<12){
                    month=month+1;
                    day=1;
                }
                else{
                    month=1;
                    day=1;
                    year=year+1;
                }
                System.out.print(year+"-"+month+"-"+day);
            }
    }
    
    度量:(方法和类)
    Method CogC ev(G) iv(G) v(G)
    secondpta.fourth.checkInputValidity(int,int,int) 6 1 6 10
    secondpta.fourth.isLeapYear(int) 3 1 1 4
    secondpta.fourth.main(String[]) 2 1 2 2
    secondpta.fourth.nextDate(int,int,int) 3 1 1 3
    Class OCavg OCmax WMC
    secondpta.fourth 2.25 3 9
    UML类图:

7-5

import java.util.Scanner;
/**
 * @author:everglow
 * @data 2021/9/21 19:02
 */

public class fifth {
        int year;
        int month;
        int day;
        public static void main(String[] args){
            Scanner input=new Scanner(System.in);
            Main data=new Main();
            data.year=input.nextInt();
            data.month=input.nextInt();
            data.day=input.nextInt();
            int n=input.nextInt();
            if(checkInputValidity(data.year,data.month,data.day)==false){
                System.out.print("Wrong Format");
            }
            else {
                System.out.print(n+" days ago is:");
                nextDate(data.year, data.month, data.day,n);
            }
        }

        public static boolean isLeapYear(int year){     //判断是否闰年
            boolean p=false;
            if((year%4==0&&year%100!=0)||year%400==0){
                p=true;
            }
            return p;
        }

        public static boolean checkInputValidity(int year,int month,int day){
            boolean x=true;
            if(!(year>=1820&&year<=2020)||!(month>=1&&month<=12)||!(day>=1&&day<=31)
                    ||(!isLeapYear(year)&&(month==2)&&(day>=29))){
                x=false;
            }
            return x;
        }
        public static void nextDate(int year,int month,int day,int n){
            int[] monthnum=new int[]{31,28,31,30,31,30,31,31,30,31,30,31};
            if(isLeapYear(year)){
                monthnum[1]=29;
            }
            if((day-n<monthnum[month-1])&&((day-n)>=1)){
                   day=day-n;
            }
            else if(month<12&&month>1){
                   if(n>=0) {
                       day = day - n + monthnum[month - 2];
                       month = month - 1;
                   }
                   else{
                       day = day - n - monthnum[month-1];
                       month = month + 1;
                   }
            }
            else{
                   if(n>=0){
                       year = year - 1;
                       day = day - n + monthnum[11];
                       month = 12;
                   }
                   else{
                       year=year+1;
                       day = day - n - monthnum[11];
                       month=1;
                   }
            }
            System.out.print(year+"-"+month+"-"+day);
        }
}
度量:(方法和类)
Method CogC ev(G) iv(G) v(G)
secondpta.Fifth.checkInputValidity(int,int,int) 6 1 6 10
secondpta.Fifth.isLeapYear(int) 3 1 1 4
secondpta.Fifth.main(String[]) 2 1 2 2
secondpta.Fifth.nextDate(int,int,int,int) 12 1 1 8
Class OCavg OCmax WMC
secondpta.Fifth 3 6 12
UML 类图:

设计与分析:

​ 7-4跟7-5题目内容相似,一个求给定日期的下一天,一个求给定日期的下N天,所以解决思路大同小异。结合7-4和7-5的UML类图来看,俩个题目UML类图几乎一样,7-5是我在7-4的基础上完成的,先看7-4,我的思路是构造一个日期类(fourth),类中属性要有年月日,将输入的年月日分别储存在类中,首先用checkInputValidity()判断输入日期的合法性,其次用isLeapyear()判断是否闰年,然后再用nextDate()求下一天,实现求下一天的具体思路是构造一个数组,存储每个月份的最大天数,根据是否闰年判断的结果如果是闰年将数组的存储2月的值改为29,否则不更改,再通过选择语句将输入日期的下一天打印出来,如果是月末就月份加1,日期置1,如果是年末,就年份加1,日期和月份都置1,7-5的思路跟7-4的思路大体相同,有点不同的就是求下N天,方法nextDate()是用来求下N天的,不同的是需要增加更多的判断语句,由N值不的不同来设定一个标界,比如N大于前面的月份或者小于后面的月份就要进行月份加减的操作,遇见年末还要进行年的加减,再进行下N天的求解,下N天与下一天相比就是下N天需要根据N的值的对日期进行操作,总体思路没有变化。

​ 再看7-4和7-5的度量,7-5的类平均圈复杂度为3,7-4的类平均圈复杂度为2.25,7-5相比7-4多了0.75,多的那点圈复杂度主要是因为求下N天的方法比求下一天的方法的圈复杂度多了5点,但是7-5比7-4实现了更多的东西,相比之下,牺牲圈复杂度换来跟更丰富的功能也是值得的。

  • 题目集3中的7-2

    ​ 题目内容为用类的设计来实现求给定一个日期的下一天,是不是很熟悉,没错,它跟题目集2的7-4所要完成的需求是一样的,但是它要求的是用设计一个日期类,用类的特性来完成题目需求,话不多说,上源码:

    package thirdpta;
    import java.util.Scanner;
    /**
     * @author:everglow
     * @data 2021/9/28 20:37
     */
    public class Second {
        public static void main(String[] args) {
            Scanner sc=new Scanner(System.in);
            Data test=new Data();
            test.setYear(sc.nextInt());
            test.setMonth(sc.nextInt());
            test.setDay(sc.nextInt());
            if(test.checkInputValidity(test.getYear(),test.getMonth(),test.getDay())==true){
                System.out.print("Next day is:");
                test.getNextDate();
            }
            else{
                System.out.print("Date Format is Wrong");
            }
        }
    }
    class Data{
        private int year;
        private int month;
        private int day;
        private int []mon_maxnum=new int[]{31,28,31,30,31,30,31,31,30,31,30,31};
        Data(){
    
        }
        Data(int year,int month,int day){
            year=year;
            month=month;
            day=day;
        }
        int getYear(){
            return year;
        }
    
        int getMonth(){
            return month;
        }
    
        int getDay(){
            return day;
        }
        void setYear(int year1){
            year=year1;
        }
    
        void setMonth(int month1){
            month=month1;
        }
    
        void setDay(int day1){
            day=day1;
        }
    
        boolean isLeapYear(int year){     //判断是否闰年
            boolean p=false;
            if((year%4==0&&year%100!=0)||year%400==0){
                p=true;
            }
            return p;
        }
    
        boolean checkInputValidity(int year,int month,int day){
            boolean x=true;
            if(!(year>=1900&&year<=2020)||!(month>=1&&month<=12)||!(day>=1&&day<=31)
                    ||(!isLeapYear(year)&&(month==2)&&(day>=29))){
                x=false;
            }
            return x;
        }
        
        void getNextDate(){
            if(isLeapYear(year)){
                mon_maxnum[1]=29;
            }
            if(day<mon_maxnum[month-1]){
                day=day+1;
            }
            else if(month<12){
                month=month+1;
                day=1;
            }
            else{
                year+=1;
                month=1;
                day=1;
            }
            System.out.print(year+"-"+month+"-"+day);
        }
    }
    
    度量:(类和方法)
    Method CogC ev(G) iv(G) v(G)
    thirdpta.Data.Data() 0 1 1 1
    thirdpta.Data.Data(int,int,int) 0 1 1 1
    thirdpta.Data.checkInputValidity(int,int,int) 6 1 6 10
    thirdpta.Data.getDay() 0 1 1 1
    thirdpta.Data.getMonth() 0 1 1 1
    thirdpta.Data.getNextDate() 4 1 1 4
    thirdpta.Data.getYear() 0 1 1 1
    thirdpta.Data.isLeapYear(int) 3 1 1 4
    thirdpta.Data.setDay(int) 0 1 1 1
    thirdpta.Data.setMonth(int) 0 1 1 1
    thirdpta.Data.setYear(int) 0 1 1 1
    thirdpta.Second.main(String[]) 2 1 2 2
    Class OCavg OCmax WMC
    thirdpta.Data 1.45 4 16
    thirdpta.Second 2 2 2
    UML类图:

设计与分析:

​ 这题跟题目集二的7-4一样,都要求给定日期的下一天,但是所要要求的代码结构不一样。结合我画出的UML类图来看,这题我是按照类的设计来完成需求的,构造一个日期类,日期的类的属性都是私有的,只能通过日期类的方法获取属性跟设置属性(UML类图中get_ set_都是设置,获取函数),方法isLeapYear()用于判断是否闰年,方法checkInputValidity()用于检验输入日期的合法性,方法getNextDate()用于求下一天,思路跟前面我讲解的一样,这题我主要用心在构造函数的封装性和健壮性。

​ 结合我对程序的度量看,先看方法,checkInputValidity()的圈复杂度最高,达到了10,其次是圈复杂度为4的getNextDate(),再看类的平均圈复杂度,由于本题我设了俩个类,一个日期类,一个Second类,单看日期类,平均圈复杂度为1.45,Second类的平均圈复杂度为2,对比题目集2的7-4程序的度量,二者相加虽然大于7-4的平均圈复杂度2.25,但是牺牲的这点复杂度却使代码变得更有条理,并且具备了JAVA类的特性(私有属性等等),程序的逻辑性也由一定程度的提高。

  • 题目集3中的7-3

​ 这题的题目需求为给定一个一元多项式,用类的设计对其进行求导并输出结果。这题是困扰我最久的题目,并且让我陷入了不断填坑填Bug得尴尬处境,先不多说,分析我的源码(由于写的很烂,所以代码会很长,可略过直接看我分析源码):

package thirdpta;
/**
 * @author:everglow
 * @data 2021/9/29 16:36
 */
import java.math.BigInteger;
import java.util.Scanner;
public class Third {
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        Polynomial poly=new Polynomial();
        String str=sc.nextLine();
        String str1=str.replaceAll(" ","");
        if(check_Fair(str1)){
            String str2=func_Takeoff(str1);
            poly.polynomial=func(str2);
            if(poly.polynomial.equals("0")){
                System.out.print("0");
            }
            else {
                poly.toarray();
                poly.getWhere();
                poly.print_Polys();
            }
        }
        else {
            System.out.println("Wrong Format");
        }
    }
    public static String func(String str){
        String result=new String();
        int a=0,b=0;
        for(int i=0;i<str.length();i++){
            if(str.charAt(i)!='*'&&str.charAt(i)!='^'){
                result=result+str.charAt(i);
            }
        }
        return result;
    }

    public static String func_Takeoff(String str){
        int a=-1,b=0;
        String result2=new String();
        String result1=new String();
        int n=0;
        for(int i=1;i<str.length();i++) {
            if (((str.charAt(i) == '+' || str.charAt(i) == '-')&&str.charAt(i-1)!='^'&&(i!=0))||i==str.length()-1){
                if(i==str.length()-1){
                    b=str.length();
                }
                else {
                    b=i;
                }
                String temp = str.substring(a+1, b);
                a = b;
                for (int j = 1; j < temp.length(); j++){
                    if (temp.charAt(j) >= '0' && temp.charAt(j) <= '9'){
                        continue;
                    }
                    else{
                        result1=result1+temp;
                        if(i!=str.length()-1) {
                            result1 = result1 + str.charAt(i);
                        }
                        n=1;
                        break;
                    }
                }
            }
        }
        if(n==1){
            if (result1.length() == 0) {
                result1 = str.substring(0, str.length());
                for (int i = 1; i < result1.length(); i++) {
                    if (result1.charAt(i) >= '0' && result1.charAt(i) <= '9') {
                        if (i == result1.length() - 1) {
                            result2 = "0";
                        }
                        continue;
                    } else {
                        result2 = str.substring(0, str.length());
                        break;
                    }
                }
            } else if (result1.charAt(result1.length() - 1) == '+' || result1.charAt(result1.length() - 1) == '-') {
                result2 = result1.substring(0, result1.length() - 1);
            } else {
                result2 = result1.substring(0, result1.length());
            }
        }
        else {
            if(str.contains("x")){
                result2=str.substring(0,str.length());
            }
            else {
                result2 = "0";
            }
        }
        return result2;
    }

    public static boolean check_Fair(String str){
        boolean p=true;
        for(int i=0;i<str.length();i++){
            if(str.charAt(i)=='^'&&str.length()>i+1){
                if(str.charAt(i+1)=='0'){
                    p=false;
                }
            }
            else if(str.charAt(i)=='+'||str.charAt(i)=='-'){
                if(str.charAt(i+1)=='0'){
                    p=false;
                }
            }
            else if(str.startsWith("0")){
                p=false;
            }
            else if(str.charAt(i)!='x'&&str.charAt(i)!='+'&&str.charAt(i)!='-'
                    &&str.charAt(i)!='*'&&str.charAt(i)!='^'&&(str.charAt(i)<'0'||str.charAt(i)>'9')){
                p=false;
            }
            else if((str.charAt(i)=='^'&&i>=1&&str.charAt(i-1)!='x')||(str.charAt(i)=='*'&&str.length()>i+1&&
                    str.charAt(i+1)!='x')){
                p=false;
            }
            else if(str.length()==1&&(str.charAt(i)<'0'||str.charAt(i)>'9')){
                p=false;
            }
        }
        return p;
    }
}
class Polynomial{
    String polynomial;
    char[] polys;
    BigInteger[] coefficients=new BigInteger[100];
    BigInteger[] indexs=new BigInteger[100];
    char[] operators=new char[100];
    int locx,locy=-1;
    int n=0;


    void toarray(){
        polys=polynomial.toCharArray();
    }

    void getWhere(){
        for(int i=0;i<polys.length;i++){
            if(polys[i]=='x'){
                locx=i;
                if(locx==locy+1){
                    coefficients[n]=BigInteger.valueOf(1);
                }
                else {
                    String temp = polynomial.substring(locy + 1, locx);
                    if(temp.equals("-")){
                        temp="-1";
                    }
                    coefficients[n] = new BigInteger(temp);
                }
            }
            else if((polys[i]=='+'||(i>=1&&polys[i]=='-'&&polys[i-1]!='x'))&&i!=0){
                locy=i;
                if(locx+1==locy){
                    indexs[n]=BigInteger.valueOf(1);
                }
                else {
                    String temp = polynomial.substring(locx + 1, locy);
                    indexs[n] = new BigInteger(temp);
                }
                operators[n]=polys[i];
                n++;
            }
            if(i==polys.length-1){
                locy=polys.length;
                if(locx+1==locy){
                    indexs[n]=BigInteger.valueOf(1);
                }
                else {
                    String temp = polynomial.substring(locx + 1, locy);
                    indexs[n] = new BigInteger(temp);
                }
            }
        }
    }
    
    void print_Polys(){
        for(int i=0;i<=n;i++){
            BigInteger x1;
            x1=coefficients[i].multiply(indexs[i]);
            if(i==0){
                System.out.print(x1);
                if(indexs[i].compareTo(BigInteger.valueOf(1))==0){

                }
                else if(indexs[i].compareTo(BigInteger.valueOf(2))==0){
                    System.out.print("*x");
                }
                else{
                    System.out.print("*x^");
                    System.out.print(indexs[i].add(BigInteger.valueOf(-1)));
                }
            }
            else{
                if((x1.compareTo(BigInteger.valueOf(0))==1)&&operators[i-1]=='+'){
                    if(indexs[i].compareTo(BigInteger.valueOf(1))==0){

                    }
                    else if(indexs[i].compareTo(BigInteger.valueOf(2))==0){
                        System.out.print("+");
                        System.out.print(x1);
                        System.out.print("*x");
                    }
                    else{
                        System.out.print("+");
                        System.out.print(x1);
                        System.out.print("*x^");
                        System.out.print(indexs[i].add(BigInteger.valueOf(-1)));
                    }
                }
                else if(x1.compareTo(BigInteger.valueOf(0))==-1&&operators[i-1]=='+'){
                    if(indexs[i].compareTo(BigInteger.valueOf(1))==0){

                    }
                    else if(indexs[i].compareTo(BigInteger.valueOf(2))==0){
                        System.out.print(x1);
                        System.out.print("*x");
                    }
                    else{
                        System.out.print(x1);
                        System.out.print("*x^");
                        System.out.print(indexs[i].add(BigInteger.valueOf(-1)));
                    }
                }
                else if(x1.compareTo(BigInteger.valueOf(0))==-1&&operators[i-1]=='-'){
                    if(indexs[i].compareTo(BigInteger.valueOf(1))==0){

                    }
                    else if(indexs[i].compareTo(BigInteger.valueOf(2))==0){
                        System.out.print("+");
                        System.out.print(x1.multiply(BigInteger.valueOf(-1)));
                        System.out.print("*x");
                    }
                    else{
                        System.out.print("+");
                        System.out.print(x1.multiply(BigInteger.valueOf(-1)));
                        System.out.print("*x^");
                        System.out.print(indexs[i].add(BigInteger.valueOf(-1)));
                    }
                }
                else if(x1.compareTo(BigInteger.valueOf(0))==1&&operators[i-1]=='-'){
                    System.out.print(operators[i-1]);
                    System.out.print(x1);
                    if(indexs[i].compareTo(BigInteger.valueOf(1))==0){

                    }
                    else if(indexs[i].compareTo(BigInteger.valueOf(2))==0){
                        System.out.print("*x");
                    }
                    else{
                        System.out.print("*x^");
                        System.out.print(indexs[i].add(BigInteger.valueOf(-1)));
                    }
                }
            }
        }
    }
}
度量:(方法与类)
Method CogC ev(G) iv(G) v(G)
thirdpta.Polynomial.getWhere() 25 1 8 13
thirdpta.Polynomial.print_Polys() 43 1 21 21
thirdpta.Polynomial.toarray() 0 1 1 1
thirdpta.Third.check_Fair(String) 23 1 22 25
thirdpta.Third.func(String) 4 1 4 4
thirdpta.Third.func_Takeoff(String) 48 9 20 21
thirdpta.Third.main(String[]) 5 1 3 3
Class OCavg OCmax WMC
thirdpta.Polynomial 9 17 27
thirdpta.Third 7.5 14 30
UML类图:

设计与分析:

​ 这题是我耗时最长的一题,并且我没有通过所有的测试点。结合源代码和UML类图,下面给我的设计思路:题目要求我们对一个简单多项式求导,于是我构造了一个多项式类(Polynomial),属性有一个用于存储多项式(这是已经处理过的)的字符串,一串用于存储多项式的每个字符的字符数组,俩个大数数组一个用于存储指数,一个用于存储系数,一串用于存储运算符的字符数组,记录位置的整型locx,locy,记录数量的整型n。我的算法思路是在主类(Third)中首先用字符串str存储输入的一元多项式,用check_fair()检验输入的一元多项式的合法性,我没有用正则表达式,也为我后面不断填bug埋下了伏笔,检验合法性的内容包括指数系数不为0,表达式必须符合规则(不能^x或者x*),因数只能是x等,若检测不合法,输出Wrong Format程序结束,否则进行下一步,用方法func_Takeoff()去除常数项,去除常数项的方法则是将表达式分成若干个由运算符相截开的子字符串,对每一个子字符串进行选择判断,判断里面是否是纯数字,如果是,则舍弃它和它前面的运算符,第三步是用方法func()去除表达式中的乘号和^符号,将其转化成一个只有x和运算符以及指数系数的处理过的字符串,处理方法是对运算符逐个字符判断,遇到需要舍弃的符号就直接丢弃,其他的加入到新的字符串并将其存储到创建的多项式类的属性字符多项式中,接下啦的操作在多项式类中进行,首先用方法toarray()对处理过的多项式转化成多项式字符数组,然后根据getWhere()找出每一个x的位置和运算符(+或者-)的位置,分别用locx和locy(locy初始为-1)存储,二者之间的数据则是指数或者系数,通过用字符串的内置方法substring(locy+1,locx)(或substring(locx+1,locy))分别截取出指数和系数子字符串,截取出的子字符串转化成大数类型,存储在指数系数的大数数组上,每当存储完一个系数,n就加一(n初始化为0),同时运算符也存储在运算符数组中,当对表达式的每个字符都判断完后,进行最后一步,计算导函数并输出,方法print_Polys()根据运算符数组的符号跟指数系数相乘的正负性来选择输出特定的样式,大数相乘用的是内置方法x1.multiply(x2),根据结果的正负性,结合存储的运算符来决定输出的表达式的运算符,系数为1,不输出x只输出指数系数相乘的积,系数为2,只输出相乘的机和x,系数既不等于2也不等于1,输出正常的格式,我的思路大体就是这样,思路是没问题的,但是没有考虑到健壮性,有些特殊情况可能就会出错。

​ 再看我对类和方法的度量,显而易见有些数值超标了,先看方法,我在做方法的复杂度分析时,软件就已经自动标红了我的某些方法,圈复杂度超过20的方法我有3个,print_Polys(),check_Fair(String),func_Takeoff(String),足以见得程序的条理性健壮性并不好,当然造成这个原因的也有一定程度上是我在不断填bug不断增加程序的复杂度而导致的,但是不断填bug就已经表明这不是一个健壮性好的程序,再看我类的复杂度分析,Third类圈复杂度为7.5,Polynomial类圈复杂度为9,二者相加16.5,虽说这题比之前的题目更复杂,但是多出来这么多圈复杂度属实不应该,牺牲了这么多却没有完全完成题目需要的需求的,显然这是一段失败的尝试,但是通过分析自己的代码,也能收获自己的不足,获得改进。

三. 踩坑心得

  1. 首先踩的第一个坑就是题目集1的7-8,因为没有注意浮点型数据的特性,错误地将直角三角形的判断条件直接与数学逻辑相等(a2+b2=c2),但其实不是,判定条件应该是c2-a2-b2<0.1(后面数值0.1可以改小但是得大于0),原因我上面对7-8源码分析的时候已经解释过了,简单来说就是浮点型数据的位数比较多,存储的数据与你输入的数据并不一定完全对等。
  2. 踩的第二个坑是做题目集二的7-4的时候错误的忽视了判定闰年的条件,判定闰年的条件是n%4==0&&n%100!=0或者n%400=0,而我当时以为俩个条件只需要一个就可以判断闰年,但是其实并不是,俩个条件都要写上才不会漏过每一个闰年,当时面对一个测试点一直过不去的时候,我一直在输出下一天的里面找错误,结果却忽视了判定闰年的方法的不全面性,奇怪的是我测试的数据也都没有错误,但是事实证明测试有的时候就是设在比较刁钻的地方,后来我通过分析源码发现是判定闰年少加了条件,加上条件后问题得以解决。因为与题目集2的7-5跟题目集三的7-2题目相类似,所以我在这另外俩题并没有踩坑,而是很顺利的过掉测试点。
  3. 第三个坑是我踩的最大一个坑,并且越陷进越深,那就是我做题目集三的7-3。首先我是看了这题的解题思路,说要用正则表达式判断多项式的合法性,我也上网查找了正则表达式的学习,并且在B站看了学习视频,但是由于资料过少,都是模板性的内容,于是我打算另辟蹊径,用自己构思的方法完成题目的需求。这题我是不断进坑不断补坑的过程,首先进的一个坑就是要是表达式以运算符开头怎么办,我的程序并没有考虑这一点,我改进的思路是从第二个字符开始判断,掠过第一个字符,把第一个字符之间当成系数的组成部分。然后我又碰到了如果输入的表达式有常数项怎么办,为此,我不得已写一个方法func_Takeoff()来去除常数项,由于需要便利整个字符串,所以产生的圈复杂度又是极高,增加了代码的复杂度。我埋下的最大的坑是思路就有问题,但是这是在我做到后面才发下有些细节根本考虑不进去,我操作的是处理过的表达式(只含有x,指数,系数,运算符),通过记录位置的方式来完成对指数系数的存储和求导后的输出,但是这样导致的问题就是我的程序分辨不出-16x-5x与-16x-5的区别,一个-5是指数,一个-5是系数,然而我的程序并不能准确的识别出而是会错误的把-5当成指数(指的是这个例子:-16x-5x),而且由于输入指数的大小不一位置不一,我甚至不能继续填坑,所以这也是我埋下的最大一个坑,怎么补也补不完。还有一个改变我代码结构的坑,大数测试这个点,但是幸运的是这个坑被我填上了,原先我用的int类型数组去存储指数系数,但是由于数据可能是大数,所以得用大数类去存储,为此,我先是自学了BigInteger类,了解了它的内置方法和属性,然后大幅度的重构我已经写好的方法,不能用=判断俩数的相等,而是得用compareto()判断俩数的相等,大数相乘也必须得用它自己特有的方法mutiliply()而不是直接相乘。


  4. 总结:我遇到的问题大致就是这些,除了题目集3的7-3的唯一一个坑填不上,其他的代码需求测试都没有问题,做的最差的也就是最后一个题,主要是自己算法思路有问题,但是又没有考虑清楚,反而做一步,走一步,导致出了很多的问题, 总体看还是程序的健壮性有待提高,逻辑思维能力要进一步加强。

四. 改进建议

  1. 对总体的题目看来,我对我自己的建议就是用类的设计去完成这些题目,要从程序的需求出发,写程序要面向对象而不是像以往一样面向过程,类的方法应该尽量简单明了,一个方法只做一个功能,不要在一个方法里增加太多的圈复杂度,其次就是类的属性如果不是公共类的话尽量把属性设为私有属性,提高程序的封装性可靠性。
  2. 对具体的题目改进的话,我觉得对于前面那几题日期类的题目,可以适当通过梳理逻辑性增加点对点的方法减少方法的圈复杂度,提高整个代码的整洁度。对于我问题最大的那个题目,也就是题目集三的7-3的话,我给我自己的建议就是,首先自学一下正则表达式,不仅因为是题目需要,在以后的应用中,也会经常用到正则表达式,正则表达式是我们很重要的一个工具,然后从我原先的思路对照别人的思路思考,总结出经验,避免下次出错,最后就是重构代码,由于我没有使用正则表达式,整个类与方法的结构性都需要改变,但这也是必经之路,这也是一个很重要的学习过程。用类的设计去完成需求,并且做到一个方法对应一项功能,不要冗余,不要徒增复杂度。

五. 总结

  1. 这三次题目集让我循序渐进的从面向过程过渡到面向对象,学习到的内容也有很多,比如说JAVA语言的基本语法,JAVA一些重要的类(String,BigIngeter),数组的基本使用,以及对类的设计和需要的兼顾的类的特性。还有一个比较重要的学习到的应该算是代码的调试与分析吧,通过这三次题目以及写这个博客,我学习到了怎么用工具去分析自己代码的圈复杂度,以及怎么去测试我的代码的健壮性。
  2. 我需要学习的点倒是还挺多的,首先就是要提高自己的算法思维能力,提高自己程序的健壮性,用面向对象的思维去解决题目的需求。细致到具体来看的话,我需要去学习一下正则表达式(这个可以多去CSDN或者博客园或者B站上学习别人发布的教程),了解一些JAVA编程的资料,做完自己的题目,可以结合自己的思路对照其他人更好的思路来提高自己的思维能力以及多面性。
  3. 对课程的建议话就是我觉得老师可以适当增加实操内容,可以布置自学内容供我们自学,或者说是给出一些学习建议供我们参考,或者提供一些实用的学习资料。
posted @ 2021-10-15 15:13  everglow1019  阅读(117)  评论(0)    收藏  举报