面向对象程序设计第一次博客

1、前言

  • 题目集一的知识点我觉得重在考察java的基本语法,和之前学的c语言差不多,只是一些方面的语法有了 变化,题目有八道题,体量虽多,但是相对来说偏向简单。
  • 题目集二的知识点就已经偏向java的范围了,不只是单纯的考察基本语法,同时新增了对java封装方法的使用,还考察了对java方法以及java数组的使用,题目有五道题,比上一次的题目减少了三道,但是难度提升了,也对我们的逻辑性进行了考察。
  • 题目集三的知识点已经涉及到了对类的设计和编写,以及对类的封装性的应用,同时还有设计多个类之间的关系,题目有三道题,难度大大增加,不只是考察逻辑性,同时对细节性和类的关系的思考都有考察,也对学生的心性和自学能力进行了较深的考察。

2、设计与分析

  1. 题目集一 7-8 判断三角形类型
  • 源码
    `

    import java.util.Scanner;

    public class Main {

    public static void main(String[] args) {
    Scanner input = new Scanner(System.in);
    double a=input.nextDouble();
    double b=input.nextDouble();
    double c=input.nextDouble();

    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(ab&&ac) {
    System.out.print("Equilateral triangle");
    }
    else if((ab||ac||bc)&&((aa+bb-cc<0.000001)||(aa+cc-bb<0.000001)||(bb+cc-a*a<0.000001))) {
    System.out.print("Isosceles right-angled triangle");
    }
    else if(a
    b||ac||bc) {
    System.out.print("Isosceles triangle");
    }
    else if((aa+bb-cc<0.000001)||(aa+cc-bb<0.000001)||(bb+cc-a*a<0.000001)) {
    System.out.print("Right-angled triangle");
    }
    else {
    System.out.print("General triangle");
    }
    }
    }
    }

    }

  • SourceMonitor生成报表:

image

  • 由图可知圈复杂度为22,该题我运用了大量的if-else语句来判断,是一个非常复杂、低效的代码,由于是刚刚接触圈复杂度,所以没有太过注意,可以用更简便的方法来判断此题的结论,比如设置一个类,把输入的三条边传入类里面,然后在类里面用相应的方法判断是属于哪种三角形,if-else嵌套太多,导致圈复杂度大幅上升,在以后的学习中我会尽量避免多用if-else语句。
  • 解题思路是先判断三条边能不能组成三角形,然后再按照等边三角形、等腰直角三角形、等腰三角形、直角三角形、三角形依次判断最后得出结论并输出。
  1. 题目集二 7-4 求下一天
  • 源码
        import java.util.Scanner;

      public class Main {
	    public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		int year = input.nextInt();
		int month = input.nextInt();
		int day = input.nextInt();
		boolean flag = false;
		flag = checkInputValidity(year, month, day);
		if(flag) {
			nextDate(year,month,day);
		} else {
			System.out.println("Wrong Format");
		}
	}
	public static boolean isLeapYear(int year) {
		if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
			return true;
		} else {
			return false;
		}
	}
	public static boolean checkInputValidity(int year, int month, int day) {
		if (year < 1820 || year > 2020 || month < 1 || month > 12 || day < 1 || day > 31) {
			return false;
		} else {
			boolean flag = false;
			flag = isLeapYear(year);
			if (flag) {
				if (month == 4 || month == 6 || month == 9 || month == 11) {
					if (day > 30) {
						return false;
					} else {
						return true;
					}
				} else if (month == 2) {
					if (day > 29) {
						return false;
					} else {
						return true;
					}
				} else {
					return true;
				}
			} else {
				if (month == 4 || month == 6 || month == 9 || month == 11) {
					if (day > 30) {
						return false;
					} else {
						return true;
					}
				} else if (month == 2) {
					if (day > 28) {
						return false;
					} else {
						return true;
					}
				} else {
					return true;
				}
			}
		}
	}
	public static void nextDate(int year,int month,int day) {
        boolean flag = false;
		flag = isLeapYear(year);
		if(month==12&&day==31) {
			year++;
			month=1;
			day=1;
			System.out.println("Next date is:"+year+"-"+month+"-"+day);
		}
        else if((flag&&month==2&&day==29)||(!flag&&month==2&&day==28)){
            month++;
			day=1;
			System.out.println("Next date is:"+year+"-"+month+"-"+day);
        }
		else if((month == 4 || month == 6 || month == 9 || month == 11)&&day==30){
			month++;
			day=1;
			System.out.println("Next date is:"+year+"-"+month+"-"+day);
		}
		else if((month == 1||month==3||month==5||month==7||month==8||month==10)&&day==31) {
			month++;
			day=1;
			System.out.println("Next date is:"+year+"-"+month+"-"+day);
		}
		else {
			day++;
			System.out.println("Next date is:"+year+"-"+month+"-"+day);
		}
	}
  }
  • SourceMonitor生成报表:

  • 由图可分析圈复杂度为30,也是和上一题一样的运用了多种的if-else语句,以及多种的if-else语句嵌套循环,在之后的改进中,要是再次碰到类似的这种判断多的题目,我会选择用switch语句来进行判断操作,同时将所有的日期存在一个数组里面,判断的时候就可以直接调用数组元素,不需要写多种if语句,同时还可以封装一个或者多个类,对类的引用可以减少圈复杂度,今后会多多注意。
  • 解题思路是先判断输入的三个数是否是正确的,然后根据是否是闰年来判断数的正确性,最后在用nextDate方法来输出上一天。
  1. 题目集二 7-5 求前N天
  • 代码

    import java.util.Scanner;

      public class Main {
	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		int year = input.nextInt();
		int month = input.nextInt();
		int day = input.nextInt();
		int n = input.nextInt();

		if (year < 1820 || year > 2020 || month < 1 || month > 12 || day < 1 || day > 31) {
			System.out.println("Wrong Format");
		} else {
			boolean flag = false;
			flag = isLeapYear(year);
			if (flag) {
				if (month == 4 || month == 6 || month == 9 || month == 11) {
					if (day > 30) {
						System.out.print("Wrong Format");
					} else {
						Date(year, month, day, n);
					}
				} else if (month == 2) {
					if (day > 29) {
						System.out.print("Wrong Format");
					} else {
						Date(year, month, day, n);
					}
				} else {
					Date(year, month, day, n);
				}
			} else {
				if (month == 4 || month == 6 || month == 9 || month == 11) {
					if (day > 30) {
						System.out.print("Wrong Format");
					} else {
						Date(year, month, day, n);
					}
				} else if (month == 2) {
					if (day > 28) {
						System.out.print("Wrong Format");
					} else {
						Date(year, month, day, n);
					}
				} else {
					Date(year, month, day, n);
				}
			}
		}
	}

	public static boolean isLeapYear(int year) {
		if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
			return true;
		} else {
			return false;
		}
	}

	public static void Date(int year, int month, int day, int n) {
		boolean flag = false;
		flag = isLeapYear(year);
		if (n < 0) {
			if (month == 4 || month == 6 || month == 9 || month == 11) {
				if (day - n >= 30) {
					month++;
					day = day - n - 30;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			} else if (month == 12) {
				if (day - n >= 31) {
					year++;
					month=1;
					day = day - n - 31;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			} else if (flag && month == 2) {
				if (day - n >= 29) {
					month++;
					day = day - n - 29;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			} else if (!flag && month == 2) {
				if (day - n >= 28) {
					month++;
					day = day - n - 28;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			} else {
				if (day - n >= 31) {
					month++;
					day = day - n - 31;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			}
		} else {
			if (month == 5 || month == 7 || month == 10 || month == 12) {
				if (day - n <= 0) {
					month--;
					day = 30 + (day - n);
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			} else if (flag && month == 3) {
				if (day - n <= 0) {
					month--;
					day = 29 + (day - n);
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			} else if (!flag && month == 3) {
				if (day - n <= 0) {
					month--;
					day = 28 + (day - n);
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			} else if (month == 1) {
				if (day - n <= 0) {
					year--;
					month=12;
					day = 31 + (day - n);
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			} else {
				if (day - n <= 0) {
					month--;
					day = 31 + (day - n);
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			}
		}
	}
}
  • SourceMonitor生成报表:

  • 由图分析圈复杂度为43,圈复杂度太高,程序可读性差,还是一样的在写程序的时候没有注意圈复杂度,选择嵌套语句太多,通篇都是选择,可以把几乎所有的if语句改成switch,圈复杂度可大大降低,未设置类,思想还停留在c语言的思想,没有过渡到面向对象思想,思想上要改变。

  • 解题思路是先判断输入的数据是否正确,然后再判断是否是闰年,最后根据输入的前n天来调用date方法计算并输入前n天。

  1. 题目集三 7-2 定义日期类
  • 代码
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);

		int year = input.nextInt();
		int month = input.nextInt();
		int day = input.nextInt();

		Date date = new Date();
		date.setYear(year);
		date.setMonth(month);
		date.setDay(day);
		
		boolean flag = false;
		flag = date.checkInputValidity();
		if(flag) {
			date.getNextDate();
		}
		else {
			System.out.println("Date Format is Wrong");
		}
		
	}
}

class Date {
	private int year;
	private int month;
	private int day;
	private int[] mon_maxnum = new int[] { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

	public Date() {
		super();
		// TODO Auto-generated constructor stub
	}

	public Date(int year, int month, int day) {
		super();
		this.year = year;
		this.month = month;
		this.day = day;
	}

	public int getYear() {
		return year;
	}

	public void setYear(int year) {
		this.year = year;
	}

	public int getMonth() {
		return month;
	}

	public void setMonth(int month) {
		this.month = month;
	}

	public int getDay() {
		return day;
	}

	public void setDay(int day) {
		this.day = day;
	}

	public boolean isLeapYear(int year) {
		if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
			return true;
		} else {
			return false;
		}
	}

	public boolean checkInputValidity() {
		if (year < 1900 || year > 2000 || month < 1 || month > 12 || day < 1 || day > 31) {
			return false;
		} else {
			boolean flag = false;
			flag = isLeapYear(year);
			if (flag) {
				switch (month) {
				case 4:
				case 6:
				case 9:
				case 11:
					if (day > mon_maxnum[4]) {
						return false;
					} else {
						return true;
					}
				case 2:
					if (day > 29) {
						return false;
					} else {
						return true;
					}
				default:
					return true;
				}
			} else {
				switch (month) {
				case 4:
				case 6:
				case 9:
				case 11:
					if (day > mon_maxnum[4]) {
						return false;
					} else {
						return true;
					}
				case 2:
					if (day > 28) {
						return false;
					} else {
						return true;
					}
				default:
					return true;
				}
			}
		}
	}

	public void getNextDate() {
		boolean flag = false;
		flag = isLeapYear(year);
		if (month == 12 && day == mon_maxnum[1]) {
			year++;
			month = 1;
			day = 1;
			System.out.println("Next day is:" + year + "-" + month + "-" + day);
		} else if ((flag && month == 2 && day == 29) || (!flag && month == 2 && day == mon_maxnum[2])) {
			month++;
			day = 1;
			System.out.println("Next day is:" + year + "-" + month + "-" + day);
		} else if ((month == 4 || month == 6 || month == 9 || month == 11) && day == mon_maxnum[4]) {
			month++;
			day = 1;
			System.out.println("Next day is:" + year + "-" + month + "-" + day);
		} else if ((month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == mon_maxnum[1]) && day == 31) {
			month++;
			day = 1;
			System.out.println("Next day is:" + year + "-" + month + "-" + day);
		} else {
			day++;
			System.out.println("Next day is:" + year + "-" + month + "-" + day);
		}
	}

}
  • SourceMonitor生成报表:

  • PowerDesigner类图:

  • 由报表可知圈复杂度为22,创建了一个类,并且主方法引用,相应的计算方法都是在Date类之间,但是还是引用了多种的if-else语句,判断的时候嵌套太多导致圈复杂度并不是很好,在之后的写代码中会多加注意圈复杂度的判断。

  • 解题思路在类图中已经体现了,是在主方法中输入,然后将输入的数据全部导入到类里面,然后在类里面进行操作和计算并且输出,运用了多个方法交替。

  1. 题目集三 7-3 一元多项式求导
  • 代码

import java.math.BigInteger;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);

		String sum = input.nextLine();
		String s = sum.replaceAll("\\s", "");

		for (int i = 0; i < s.length(); i++) {
			if (s.charAt(i) == '0') {
				if (!Character.isDigit(s.charAt(i - 1))) {
					System.out.print("Wrong Format");
					System.exit(0);
				}
			}
		}

		int flag = 1;
		for (int i = 0; i < s.length(); i++) {
			if (s.charAt(i) == 'x') {
				flag = 0;
			}
		}

		if (flag == 1) {
			System.out.print("0");
			System.exit(0);
		}

		Pattern p = Pattern.compile("(([+-]?\\d*)(\\*)(x)(\\^)([+-]?\\d+))|(([+-]?\\d)(\\*x)(?!\\^))|((?<!\\*)([+-])?(x)(\\^)([+-]?\\d+))|(((?<=)([+-]?)(x)(?!\\^)))");

		Matcher m = p.matcher(s);

		int j = 0;
		while (m.find()) {
			Circle cir = new Circle();
			cir.setS(m.group());
			cir.Find(j);
			j++;
		}
	}
}

class Circle {
	String s;

	public Circle() {
		super();
		// TODO Auto-generated constructor stub
	}

	public Circle(String s) {
		super();
		this.s = s;
	}

	public String getS() {
		return s;
	}

	public void setS(String s) {
		this.s = s;
	}

	public void Find(int j) {
		Pattern p1 = Pattern.compile("([+-]?\\d*)(\\*)(x)(\\^)([+-]?\\d+)");
		Pattern p2 = Pattern.compile("([+-]?\\d)(\\*x)(?!\\^)");
		Pattern p3 = Pattern.compile("(?<!\\*)(([+-])?(x)(\\^)([+-]?\\d+))");
		Pattern p4 = Pattern.compile("((?<!\\*)[+-]?(x)(?!\\^))");

		Matcher m1 = p1.matcher(s);
		Matcher m2 = p2.matcher(s);
		Matcher m3 = p3.matcher(s);
		Matcher m4 = p4.matcher(s);

		if (m1.find()) {
			BigInteger m = new BigInteger(m1.group(1));
			BigInteger n = new BigInteger(m1.group(5));
			BigInteger o = m.multiply(n);

			BigInteger nnn = new BigInteger("1");
			BigInteger nnn1 = new BigInteger("0");
			BigInteger n1 = n.subtract(nnn);
			if (o.compareTo(nnn1) == 1 && j != 0) {
				System.out.print("+");
			}
			if (!n1.equals(nnn1)) {
				System.out.print(o.toString() + "*x^" + n1.toString());
			} else {
				System.out.print(o.toString());
			}
		}

		if (m2.find()) {
			BigInteger mm = new BigInteger(m2.group(1));

			BigInteger o = mm;
			BigInteger nnn1 = new BigInteger("0");
			if (o.compareTo(nnn1) > 0 && j != 0) {
				System.out.print("+");
			}
			System.out.print(o.toString());
		}
		if (m3.find()) {
			BigInteger mm1 = new BigInteger(m3.group(5));
			BigInteger nnn = new BigInteger("-1");
			BigInteger nnn1 = new BigInteger("0");
			BigInteger o = mm1;
			BigInteger n1 = mm1.add(nnn);

			if (m3.group(0).charAt(0)=='-') {
				o = o.multiply(nnn);
			}
			if (o.compareTo(nnn1) == 1 && j != 0) {
				System.out.print("+");
			}
			System.out.print(o.toString() + "*x^" + n1.toString());
		}

		if (m4.find()) {
			if (m4.group(0).charAt(0) == '+' && j != 0) {
				System.out.print("+");
			} else if (m4.group(0).charAt(0) == '-') {
				System.out.print("-");
			}
			System.out.print("1");
		}

	}

}
  • SourceMonitor生成报表:

  • PowerDesigner类图:

  • 由报表可知圈复杂度为17,创建了一个Circle类,在类里面判断正则表达式的提取,if语句还是用的比较多,但是比起前几此作业来说,还算是有点进步,但是还是要多多注意圈复杂度的限制。

  • 解题思路是先从主方法中输入一个多项式字符串,并且判断字符串是否合法,然后用设置的第一个正则表达式将读取到的单个项传入类中,在类中设置的四个正则表达式来判断输入的项是对应着哪一个正则表达式,判断正确则应用相应的算法,最后在类里面进行输出操作。

3、踩坑心得

  • 题目集一让我做了许久的就是7-4以及7-8
    7-4是因为数据太多而且数据庞大,算法的设计也是比较复杂,然后就导致最后的提交没有通过所有的数据,后面仔细的检查了许久才发现问题,在写代码的过程中一定要细心,不然最后过不了还得重新开始检查甚至重新再写过一份。
    7-8也是花时间比较多的一道题,判断三角形,我在刚开始写的时候,把等腰三角形放在了第一个判断方向内,就导致了输入的数据是等边三角形之后显示的是等腰三角形,错误如下:
if(a==b||a==c||b==c) {
	System.out.print("Isosceles triangle");
}
else if(a==b&&a==c) {
	System.out.print("Equilateral triangle");
}

这个错误也是自己的逻辑没有弄清楚导致的顺序错误,当我把等边三角形放在第一位的时候解决,解决后如下:

if(a==b&&a==c) {
	System.out.print("Equilateral triangle");
}
else if((a==b||a==c||b==c)&&((a*a+b*b-c*c<0.000001)||(a*a+c*c-b*b<0.000001)||(b*b+c*c-a*a<0.000001))) {
	System.out.print("Isosceles right-angled triangle");
}
else if(a==b||a==c||b==c) {
	System.out.print("Isosceles triangle");
}
else if((a*a+b*b-c*c<0.000001)||(a*a+c*c-b*b<0.000001)||(b*b+c*c-a*a<0.000001)) {
	System.out.print("Right-angled triangle");
}
else {
	System.out.print("General triangle");
}

在我解决了这个问题之后又发现在直角三角形和等腰直角三角形判断发现了错误,查阅资料后才知道原来是double类型的精度问题,将aa+bb==cc换成aa+bb-cc<0.000001后解决。

  • 题目集二的7-4和7-5其实是同一个类型的题目,只是需要判断计算的方法不一样,在题目集二中,最开始没有考虑的问题是闰年二月份有29天而导致错误,修改如下后解决:
flag = isLeapYear(year);
if (flag) {
	if (month == 2) {
		if (day > 29) {
			return false;
		} else {
			return true;
		}
	}
}

在7-5中有比较严谨的计算下一天的算法,最初想法是直接用日期去减或者加,然后发现数据超出了本月的范围之后没有办法解决,就直接加上了判断是否超出改约的天数,具体解决算法如下:

	public static void Date(int year, int month, int day, int n) {
		boolean flag = false;
		flag = isLeapYear(year);
		if (n < 0) {
			if (month == 4 || month == 6 || month == 9 || month == 11) {
				if (day - n >= 30) {
					month++;
					day = day - n - 30;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			} else if (month == 12) {
				if (day - n >= 31) {
					year++;
					month=1;
					day = day - n - 31;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			} else if (flag && month == 2) {
				if (day - n >= 29) {
					month++;
					day = day - n - 29;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			} else if (!flag && month == 2) {
				if (day - n >= 28) {
					month++;
					day = day - n - 28;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			} else {
				if (day - n >= 31) {
					month++;
					day = day - n - 31;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			}
		} else {
			if (month == 5 || month == 7 || month == 10 || month == 12) {
				if (day - n <= 0) {
					month--;
					day = 30 + (day - n);
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			} else if (flag && month == 3) {
				if (day - n <= 0) {
					month--;
					day = 29 + (day - n);
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			} else if (!flag && month == 3) {
				if (day - n <= 0) {
					month--;
					day = 28 + (day - n);
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			} else if (month == 1) {
				if (day - n <= 0) {
					year--;
					month=12;
					day = 31 + (day - n);
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			} else {
				if (day - n <= 0) {
					month--;
					day = 31 + (day - n);
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				} else {
					day = day - n;
					System.out.print(n + " days ago is:" + year + "-" + month + "-" + day);
				}
			}
		}
	}

算法很复杂,之后也是要注意算法的复杂度,越简单越好,在之后的改正之间也可以清楚的看出那个地方除了错误,而不是像之前那样一行行代码去寻找错误的地方。

  • 题目集三中的7-2定义日期类,在做题的过程中没有完全了解类的封装性的概念,所以就在类里面进行普通方法一样的操作,错误如下:

在之后了解了类的封装性之后,发现根本就不需要上图中圈住的内容,直接调用就行了吗,这是对类的封装性初步的理解,在类之中可以直接调用类的属性。

7-3是目前来说做的最难的一道题,也是花时间最久的一道题,这道题需要用到正则表达式的相关知识,但是正则表达式之前是从来没有接触过的一种全新的方法,正则表达式的功能强大,但是对于我来说确实是一个挑战,各种各样的语法,各种各样的调试,好在最后还是会用了,csdn上面的文章对于我来说写的比较广泛,我在看完之后还是不明白到底怎么去使用正则表达式,最后经过了很长时间的尝试才通过,在解题的最开始,我的思路是遍历整个多项式字符串,然后找到了相对应的就直接输出,但是在我的测试中发现,不管怎样尝试,输出的顺序永远都是哪个表达式放前面就输出哪个式子,没有一点的顺序,错误代码具体如下:

		Pattern p = Pattern.compile("([+-]?\\d*)(\\*)(x)(\\^)([+-]?\\d+)");
		Pattern p1 = Pattern.compile("([+-]?\\d*)(\\*)(x)");
		Matcher m1 = p.matcher(s);
		Matcher m2 = p1.matcher(s);

		String[] a = new String[2000];
		for (int i = 0; i < 2000; i++) {
			int j = 0;
			while (m1.find()) {
				a[i] = m1.group();
				int m = Integer.parseInt(m1.group(1));
				int n = Integer.parseInt(m1.group(5));
				if (m != 0 && n != 0) {
					int o = m * n;
					int n1 = n - 1;
					if (o > 0 && j != 0) {
						System.out.print("+");
					} 
					if (n1 != 0) {
						System.out.print(o + "*x^" + n1);
					} else {
						System.out.print(o);
					}

				}
				j++;
			}
			
			int k = 0;
			while (m2.find()) {
				a[i] = m2.group();
				int mm = Integer.parseInt(m2.group(1));
				if (mm != 0) {
					int o = mm;
					if (o > 0 && k != 0) {
						System.out.print("+");
					}
					System.out.print(o);
				}
				k++;
			}
			
			
		}

这个时候也是没想过用类来解决这道题,然后就导致一个我无法解决的问题,那就是顺序输出错误,如下图:

尝试了许多次没有结果之后我对源码进行了大改动,除了前面的判断是否错误没有改动,后面的几乎全部换了方法,改正后的方法如下:
先把多项式一个项拆开,放入类之中判断:

		Pattern p = Pattern.compile("(([+-]?\\d*)(\\*)(x)(\\^)([+-]?\\d+))|(([+-]?\\d)(\\*x)(?!\\^))|((?<!\\*)([+-])?(x)(\\^)([+-]?\\d+))|(((?<=)([+-]?)(x)(?!\\^)))");

		Matcher m = p.matcher(s);

		int j = 0;
		while (m.find()) {
			Circle cir = new Circle();
			cir.setS(m.group());
			cir.Find(j);
			j++;
		}

上面的正则表达式有着所有多项式的情况,类的具体判断源码如下:

	public void Find(int j) {
		Pattern p1 = Pattern.compile("([+-]?\\d*)(\\*)(x)(\\^)([+-]?\\d+)");
		Pattern p2 = Pattern.compile("([+-]?\\d)(\\*x)(?!\\^)");
		Pattern p3 = Pattern.compile("(?<!\\*)(([+-])?(x)(\\^)([+-]?\\d+))");
		Pattern p4 = Pattern.compile("((?<!\\*)[+-]?(x)(?!\\^))");

		Matcher m1 = p1.matcher(s);
		Matcher m2 = p2.matcher(s);
		Matcher m3 = p3.matcher(s);
		Matcher m4 = p4.matcher(s);

		if (m1.find()) {
			BigInteger m = new BigInteger(m1.group(1));
			BigInteger n = new BigInteger(m1.group(5));
			BigInteger o = m.multiply(n);

			BigInteger nnn = new BigInteger("1");
			BigInteger nnn1 = new BigInteger("0");
			BigInteger n1 = n.subtract(nnn);
			if (o.compareTo(nnn1) == 1 && j != 0) {
				System.out.print("+");
			}
			if (!n1.equals(nnn1)) {
				System.out.print(o.toString() + "*x^" + n1.toString());
			} else {
				System.out.print(o.toString());
			}
		}

		if (m2.find()) {
			BigInteger mm = new BigInteger(m2.group(1));

			BigInteger o = mm;
			BigInteger nnn1 = new BigInteger("0");
			if (o.compareTo(nnn1) > 0 && j != 0) {
				System.out.print("+");
			}
			System.out.print(o.toString());
		}
		if (m3.find()) {
			BigInteger mm1 = new BigInteger(m3.group(5));
			BigInteger nnn = new BigInteger("-1");
			BigInteger nnn1 = new BigInteger("0");
			BigInteger o = mm1;
			BigInteger n1 = mm1.add(nnn);

			if (m3.group(0).charAt(0)=='-') {
				o = o.multiply(nnn);
			}
			if (o.compareTo(nnn1) == 1 && j != 0) {
				System.out.print("+");
			}
			System.out.print(o.toString() + "*x^" + n1.toString());
		}

		if (m4.find()) {
			if (m4.group(0).charAt(0) == '+' && j != 0) {
				System.out.print("+");
			} else if (m4.group(0).charAt(0) == '-') {
				System.out.print("-");
			}
			System.out.print("1");
		}

	}

上面的方法中包含了所有多项式分开的情况,但是写到了课题时间截止,我还是没有发现最后的错误在哪:

合法综合测试是什么我到现在还不知道,没有拿满分。

  • 正则表达式的调试也是进行了很久很久,最后才能把一个单独的多项式具体的提取出来,最开始提取ax^b时用的是
    ([+-]?\\d*)(\\*)(x)(\\^)([+-]?\\d+)
    这种类型的多项式很容易提取,难的是后面三个:a
    x,x^b,x这三项
    当我提取ax时,前面的多项式axb中的a*x一样会提取,所以我加了一个后限制条件?!//解决,这个限制条件的意思时在匹配的表达式后方不能出现^字符,完整如下:
    ([+-]?\\d)(\\*x)(?!\\^)
    同样的,若是不加上限制条件,那么提取x^b和x单项的时候也会匹配到前面已经匹配的多项式中的项,所以这两个特殊的项我同样的也加上了限制条件,在java书中知道了环视操作这个方法:
    (?=) 肯定式向前查看
    (?!) 否定式向前查看
    (?<=) 肯定式向后查看
    (?<!) 否定式向后查看

然后我提取x^b和x的具体正则表达式就变成了这样:
(?<!\\*)(([+-])?(x)(\\^)([+-]?\\d+))
((?<!\\*)[+-]?(x)(?!\\^))

直到这个时候我才能完整的把所有的多项式给完整的提取出来。
正则表达式的功能强大,之后的学习中一定也能用到很多。

  • 在题目的测试点中还有一个大数运算,我发现这个所谓的大数,long long类型都会超出,然后又去网上学了学大数的运算规则和方法:
import java.math.BigInteger;
BigInteger m = new BigInteger(m1.group(1));
BigInteger n = new BigInteger(m1.group(5));
BigInteger o = m.multiply(n);

BigInteger nnn = new BigInteger("1");
BigInteger nnn1 = new BigInteger("0");
BigInteger n1 = n.subtract(nnn);

为了这道题真是学了挺多的,到了最后也没写出来满分还是很遗憾的。

4、改进建议

  • 圈复杂度,之前是第一次接触圈复杂度这东西,觉得没什么需要注意的地方,当我修改代码的时候才知道圈复杂度的重要性,圈复杂度越小的代码,就越清晰和容易修改,比如题目集一的7-4和7-8,题目集二的7-4和7-5,在这些题目中代码的圈复杂度都特别高,在题目集二中的7-4和7-5还有7-3中,可以把相对应的判断日期的if语句用switch对待,可以把所有的日期存入数组中方便调用,这些未修改的代码可读性极差,修改难度极高,我之前不注意写的一堆垃圾代码改起来基本上是全部修改了,几乎相当于重写一份,在今后的写代码中我会多加注意圈复杂度。
  • 对类的应用,之前的代码还停留在c语言的思想,没有向面向对象的思想转变,就不太喜欢用类来做题,其实用类来做题的时候还是很方便的,比如在题目集二的7-4和7-5中,可以把判断闰年做成一个类,可以把判断是否输入正确做成一个类,还可以把计算算法做成一个类,对类的使用很方便,代码简单清晰,一眼就能看懂,老师说过世界上万事万物都能做成类,在今后的写代码中也得要多多应用类,而且要明白类之间的关系,尽量做到耦合性最低。
  • 单一职责原则,这是很重要的一个方法,一个类只能做一件事,一个方法只能做一件事情,类与类之间的关系要明朗,两个类之间最好没有相关联的关系,在题目集三的7-3中,我设置的方法几乎都在主方法中,应该设置与功能数量相对应的类的数量,进行代码的优化,在以后的代码中我也会注意单一职责原则,一个类就做一件事,代码的可读性会大大提高。
  • 对正则表达式的精进,正则表达式是一个非常强大的方法,可用的方向太多了,仅仅一个星期我学的只是一个皮毛,在之后肯定会多多使用正则表达式,记住相关的语法。

5、总结

  • 三次题目集一次比一次难,老师说过题目集的难度是迭代的,越到后面越难,不管怎样我都会尽全力的去完成。
  • 学到了很多,圈复杂度的优化,正则表达式的读取,类的封装和使用,类的单一职责原则,正则表达式的环视操作,类之间的关系设置,代码的简化优化,还有现在的博客的一些方法,maekdown的一些语法。
  • 正则表达式还需要进一步的研究,还有类之间的关系我并没有特别的清楚,还需要多加学习,圈复杂度想要达到一定的数值,还需要多加练习。
  • 作业其实我觉得挺好的,具有挑战性,充分的利用一切的课余时间才可能写完,实验也是如此,老师课堂上的教学很紧凑,教的都是些最有用的干货,一节课下来真是感觉学到了不少,而且上课的东西是可以马上利用到的,上课氛围也很好,老师偶尔开几个玩笑总是能起到活跃气氛的作用,课上和课下组织方式都挺好的,我觉得不需要变化。
  • 老师总是让我们自学从来没有接触过的方法,其实我还是比较想让老师尽量能讲解一点,学生自学的进度还是比较慢的,有了老师的讲解或许会更加容易理解,也不需要讲的太过深入,点一下就行了,可能有的时候会起到点睛的作用。
posted @ 2021-04-04 18:39  繁星star  阅读(67)  评论(0)    收藏  举报