第一次博客作业
一、前言(对三次题目集的总结)
1.题目集一:相比于其他题目集而言,题目集一最为简单。对于Java的初学者而言,题目集一无非是一个练手的绝佳方式。里面大多都是一些Java的基础,比如Java的格式,输入和输出,并且其中大多只需要一个类即可完成相应功能。唯一棘手的便是7-4计算汇率,相比于其他题目而言,其中的操作量过大,导致很容易在细节上出现错误。
2.题目集二:相比于题目集一,题目集二略微提升了一些难度。在题目集二中开始运用了函数的构造方法。在主类中有着实现各种功能的方法,互相协同完成程序。同时7-1中,使用到了进制转换的方式。
3.题目集三:题目集三难度有着较大提升,开始引入多个类来完成程序。类与类之间的关联,聚集,依赖等。最重要的是,题目及7-3一元多项式求导中我们需要利用正则表达式对一元多项式中的数字进行配对,从而实现程序的功能。且因为一元多项式着本身具有的复杂,需要进行多方面的思考,才能将多种情况一一列举出来,得到最完美无缺的程序。因此他也是让我收获最大的一个题目。
二、设计与分析
题目集一:
7-8:输入三角形三条边,判断该三角形为什么类型的三角形。
输入格式:
在一行中输入三角形的三条边的值(实型数),可以用一个或多个空格或回车分隔,其中三条边的取值范围均为[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”。
代码如下:
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<b) { double X; X=a; a=b; b=X; } if(a<c){ double X; X=a; a=c; c=X; } if(a<1||a>200||b<1||b>200||c<1||c>200) { System.out.print("Wrong Format"); }else if(a>=(b+c)) { System.out.print("Not a triangle"); }else if(a==b&&b==c) { System.out.print("Equilateral triangle"); }else if(b==c&&(b*b+c*c-a*a<0.000001)) { System.out.print("Isosceles right-angled triangle"); }else if(b==c || a == b || a == c) { System.out.print("Isosceles triangle"); }else if(b*b+c*c-a*a<0.000001) { System.out.print("Right-angled triangle"); }else { System.out.print("General triangle"); } }
源码分析:
该题主要是运用了最简单的Java格式,输入三条边的值,返回三角形的类型。因此在代码之中,我首先做到的便是判断三条边之中最大的两个边。将输入的三个数字中最大的设为a,其次的设为b,同时为了防止输了数不为整形,我设置了double类型,因此输入和输出都为double。整个程序只在一个主类中完成,通过if和else连接,从而输出各种不同的情况。该题较为简单,但是单纯的使用if else会使程序代码变得枯燥,圈复杂度大,可以寻找一些更加清新的方法来实现这个程序。
题目集二:
7-4:
输入年月日的值(均为整型数),输出该日期的下一天。 其中:年份的合法取值范围为[1820,2020] ,月份合法取值范围为[1,12] ,日期合法取值范围为[1,31] 。 注意:不允许使用Java中和日期相关的类和方法。
要求:Main类中必须含有如下方法,签名如下:
public static void main(String[] args);//主方法
public static boolean isLeapYear(int year) ;//判断year是否为闰年,返回boolean类型
public static boolean checkInputValidity(int year,int month,int day);//判断输入日期是否合法,返回布尔值
public static void nextDate(int year,int month,int day) ; //求输入日期的下一天
输入格式:
在一行内输入年月日的值,均为整型数,可以用一到多个空格或回车分隔。
输出格式:
- 当输入数据非法及输入日期不存在时,输出“Wrong Format”;
- 当输入日期合法,输出下一天,格式如下:Next date is:年-月-日
代码如下:
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(); if(checkInputValidity(year,month,day)) System.out.print("Wrong Format"); else{ nextDate(year,month,day); } } public static boolean isLeapYear(int year){ if(year%400==0||(year%4==0&&year%100!=0)){ return true; }else { return false; } } public static boolean checkInputValidity(int year,int month,int day){ if(1820>year||year>2020||month<1||month>12||day<1||day>31||(!isLeapYear(year)&&month==2&&(day<1||day>28))){ return true; }else { return false; } } public static void nextDate(int year,int month,int day){ if(month==2){ if(isLeapYear(year)){ switch(month){ case 2:if(day!=29){ day++; }else{ month++;day = 1; } } } else{ switch(month){ case 2:if(day!=28){ day++; }else{ month++;day = 1;} } }}else{ switch(month){ case 1:if(day!=31){ day++;}else{ month++;day = 1;}break; case 3:if(day!=31){ day++;}else{ month++;day = 1;}break; case 4:if(day!=30){ day++;}else{ month++;day = 1;}break; case 5:if(day!=31){ day++;}else{ month++;day = 1;}break; case 6:if(day!=30){ day++;}else{ month++;day = 1;}break; case 7:if(day!=31){ day++;}else{ month++;day = 1;}break; case 8:if(day!=31){ day++;}else{ month++;day = 1;}break; case 9:if(day!=30){ day++;}else{ month++;day = 1;}break; case 10:if(day!=31){ day++;}else{ month++;day = 1;}break; case 11:if(day!=30){ day++;}else{ month++;day = 1;}break; case 12:if(day!=31){ day++;}else{ year++;month=1;day = 1;}break; }} System.out.print("Next date is:"+year+"-"+month+"-"+day); } }
源码分析:
本题要求为输入年月日的值,同时以固定格式输出下一天的值或者输入错误。同时引入了方法的格式。main类之中必须有着四种方法,一种主方法;一种判断是否为闰年的方法,并且为boolean类型,可以使得其只返回正确或者不正确;一种判断输入日期是否合法方法,返回布尔值;最后一种求输入日期的下一天的方法。在判断出日期的下一天的方法中,我使用了if else和switch共同结合的方法。这样可以大大的减小程序的圈复杂度。对于方法的声明均用public static进行。但该代码明显也有一个缺点。那便是代码的判断类型过多,switch中的case过多,需要编写者自身进行过多的思考,花费时间较多。
7-5:
输入年月日的值(均为整型数),同时输入一个取值范围在[-10,10] 之间的整型数n,输出该日期的前n天(当n > 0时)、该日期的后n天(当n<0时)。
其中年份取值范围为 [1820,2020] ,月份取值范围为[1,12] ,日期取值范围为[1,31] 。
注意:不允许使用Java中任何与日期有关的类或方法。
输入格式:
在一行中输入年月日的值以及n的值,可以用一个或多个空格或回车分隔。
输出格式:
- 当输入的年、月、日以及n的值非法时,输出“Wrong Format”;
- 当输入数据合法时,输出“n days ago is:年-月-日”
代码如下:
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(checkInputValidity(year,month,day,n)) System.out.print("Wrong Format"); else{ nextnDate(year,month,day,n); } } public static boolean isLeapYear(int year){ if(year%400==0||(year%4==0&&year%100!=0)){ return true; }else { return false; } } public static boolean checkInputValidity(int year,int month,int day,int n){ if((n<-10||n>10)||1820>year||year>2020||month<1||month>12||day<1||day>31||(!isLeapYear(year)&&month==2&&(day<1||day>28))){ return true; }else { return false; } } public static void nextnDate(int year,int month,int day,int n){ switch(month) { case 1:if(day-n>31){ month++;day=day-n-31; }else if(day-n<1){ year--;month=12;day=31+(day-n); }else{ day-=n; }break; case 2:if(isLeapYear(year)){ if(day-n>29){ month++;day=day-n-29; }else if(day-n<1){ month--;day=31+(day-n); }else{ day-=n; } }else{ if(day-n>28){ month++;day=day-n-28; }else if(day-n<1){ month--;day=31+(day-n); }else{ day-=n; } }break; case 3:if(day-n>31){ month++;day=day-n-31; }else if(day-n<1){ if(isLeapYear(year)){ month--;day=29+(day-n); }else{ month--;day=28+(day-n); } }else{ day-=n; }break; case 8:if(day-n>31){ month++;day=day-n-31; }else if(day-n<1){ month--;day=31+(day-n); }else{ day-=n; }break; case 5: case 7: case 10:if(day-n>31){ month++;day=day-n-31; }else if(day-n<1){ month--;day=30+(day-n); }else{ day-=n; }break; case 4: case 6: case 9: case 11:if(day-n>30){ month++;day=day-n-30; }else if(day-n<1){ month--;day=31+day-n; }else{ day-=n; }break; case 12:if(day-n>31){ year++;month=1;day=day-n-31; }else if(day-n<1){ month--;day=30+day-n; }else{ day-=n; }break; } System.out.print(n+" days ago is:"+year+"-"+month+"-"+day); } }
源码分析:
7-5是在7-4上的一种升级版。它从求下一天变成了求下n天。和7-4相比,我在此做了一些优化,代码的前段方法并没有什么差别,唯一有差别的便是求下n天的方法。在这个地方,我把可以用相同计算方法的月份使用case连在了一起,这样大大的减小了代码的长度,同时简洁明了。
题目集三:
7-2:
定义一个类Date,包含三个私有属性年(year)、月(month)、日(day),均为整型数,其中:年份的合法取值范围为[1900,2000] ,月份合法取值范围为[1,12] ,日期合法取值范围为[1,31] 。 注意:不允许使用Java中和日期相关的类和方法,否则按0分处理。
要求:Date类结构如下图所示:

输入格式:
在一行内输入年月日的值,均为整型数,可以用一到多个空格或回车分隔。
输出格式:
- 当输入数据非法及输入日期不存在时,输出“Date Format is Wrong”;
- 当输入日期合法,输出下一天,格式如下:Next day is:年-月-日
代码如下:
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner input = new Scanner(System.in); int a = input.nextInt(); int b = input.nextInt(); int c = input.nextInt(); Date myDate = new Date(a,b,c); if(myDate.checkInputValidity()) { System.out.println("Date Format is Wrong"); }else { myDate.getNextDate(); } } } 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%400==0||(year%4==0&&year%100!=0)){ return true; }else { return false; } } public boolean checkInputValidity(){ if(1900>this.year||this.year>2000||this.month<1||this.month>12||this.day<1||this.day>31||(!isLeapYear(this.year)&&this.month==2&&(this.day<1||this.day>28))){ return true; }else { return false; } } public void getNextDate() { if(this.month==2){ if(isLeapYear(this.year)){ switch(this.month){ case 2:if(this.day!=29){ this.day++; }else{ this.month++;this.day = 1; } } } else{ switch(this.month){ case 2:if(this.day!=28){ this.day++; }else{ this.month++;this.day = 1;} } }}else{ switch(this.month){ case 1:if(this.day!=31){ this.day++;}else{ this.month++;this.day = 1;}break; case 3:if(this.day!=31){ this.day++;}else{ this.month++;day = 1;}break; case 4:if(this.day!=30){ this.day++;}else{ this.month++;this.day = 1;}break; case 5:if(this.day!=31){ this.day++;}else{ this.month++;this.day = 1;}break; case 6:if(this.day!=30){ this.day++;}else{ this.month++;this.day = 1;}break; case 7:if(this.day!=31){ this.day++;}else{ this.month++;this.day = 1;}break; case 8:if(this.day!=31){ this.day++;}else{ this.month++;this.day = 1;}break; case 9:if(this.day!=30){ this.day++;}else{ this.month++;this.day = 1;}break; case 10:if(this.day!=31){ this.day++;}else{ this.month++;this.day = 1;}break; case 11:if(this.day!=30){ this.day++;}else{ this.month++;this.day = 1;}break; case 12:if(this.day!=31){ this.day++;}else{ this.year++;this.month=1;this.day = 1;}break; }} System.out.print("Next day is:"+year+"-"+month+"-"+day); } }
源码分析:
该题与题目集二中的题目所需实现的功能一致。但是此其运用了类的方法,功能的实现主要在类中实现。同时代码中的三个属性都为私有属性,而类中最好的情况就是类与类之间的耦合性尽量要低。求下一天的方法中无参构造方法最为有效,该码源中便是如此。无参方法中,所运用的各个参数均为本类中的参数,和main类中的参数并无关系,因此均用this.来表示。
7-3:
编写程序性,实现对简单多项式的导函数进行求解。
输入格式:
在一行内输入一个待计算导函数的表达式,以回车符结束。
输出格式:
- 如果输入表达式不符合上述表达式基本规则,则输出“Wrong Format”。
- 如果输入合法,则在一行内正常输出该表达式的导函数,注意以下几点: 结果不需要排序,也不需要化简;
- 当某一项为“0”时,则该项不需要显示,但如果整个导函数结果为“0”时,则显示为“0”;
- 当输出结果第一项系数符号为“+”时,不输出“+”;
- 当指数符号为“+”时,不输出“+”;
- 当指数值为“0”时,则不需要输出“x^0”,只需要输出其系数即可。
代码如下:
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 s = input.nextLine(); String ss = s.replaceAll(" ",""); int n = 0; int i = 0; String regex = "([-+]?([0-9]*\\.?[0-9]\\*)x\\^([+-]?[0-9]*\\.?[0-9]))|([-+]?([0-9]*\\.?[0-9]\\*)x)|([+-]?[0-9]*\\.?[0-9]+$)|([-+]?x\\^([+-]?[0-9]*\\.?[0-9]))|([-+]?x)"; String regex0 = "([-+]?[0-9]*\\.?[0-9])"; Pattern p = Pattern.compile(regex); Pattern p0 = Pattern.compile(regex0); Matcher m = p.matcher(ss); Matcher m0 = p0.matcher(ss); while (m0.find()){ int s0 =Integer.parseInt (m0.group(0)); if(s0==0) i++; } if(i>0) { System.out.print("Wrong Format"); }else while (m.find()){ String s1 = m.group(0); //System.out.print(s1+" "); Derivation d = new Derivation(s1); d.sucu(n); n++; } } } class Derivation{ private String s; public Derivation() { super(); // TODO Auto-generated constructor stub } public Derivation(String s) { super(); this.s = s; } public String getS() { return s; } public void setS(String s) { this.s = s; } public void sucu(int n) { String regex1 = "([-+]?[0-9]*\\.?[0-9])\\*"; String regex2 = "x\\^([+-]?[0-9]*\\.?[0-9])"; String regex3 = "([-+]?[0-9]*\\.?[0-9])\\*x$"; String regex4 = "(^[+-]?[0-9]*\\.?[0-9]$)"; String regex5 = "^([+-]?)x"; Pattern p1 = Pattern.compile(regex1); Pattern p2 = Pattern.compile(regex2); Pattern p3 = Pattern.compile(regex3); Pattern p4 = Pattern.compile(regex4); Pattern p5 = Pattern.compile(regex5); Matcher m1 = p1.matcher(this.s); Matcher m2 = p2.matcher(this.s); Matcher m3 = p3.matcher(this.s); Matcher m4 = p4.matcher(this.s); Matcher m5 = p5.matcher(this.s); while (m1.find()&&m2.find()){ int s1 =Integer.parseInt (m1.group(1));//字符串转化为整数 int s2 =Integer.parseInt (m2.group(1)); if(n>0&&s1*s2>0&&(s2-1)==1) { System.out.print("+"+s1*s2+"*x"); }else if(n>0&&s1*s2>0) { System.out.print("+"+s1*s2+"*x^"+(s2-1)); }else if((s2-1)==1){ System.out.print(s1*s2+"*x"); }else { System.out.print(s1*s2+"*x^"+(s2-1)); } } while(m3.find()) { int s3 =Integer.parseInt (m3.group(1)); if(s3>0) System.out.print("+"+s3); else System.out.print(s3); } while(m4.find()) { int s4 =Integer.parseInt (m4.group(1)); if(n==0) System.out.print("0"); else System.out.print(""); } while(m2.find()&&m5.find()) { int s2 =Integer.parseInt (m2.group(1)); String ss =m5.group(1); int s5 = 0; if(m5.group(0).charAt(0)=='-') { s5 = -1; }else { s5 = 1; } if(n>0&&s5*s2>0&&(s2-1)==1) { System.out.print("+"+s5*s2+"*x"); }else if(n>0&&s5*s2>0) { System.out.print("+"+s5*s2+"*x^"+(s2-1)); }else if((s2-1)==1){ System.out.print(s5*s2+"*x"); }else { System.out.print(s5*s2+"*x^"+(s2-1)); } } while(!m2.find()&&m5.find()) { String s5 =m5.group(1); if(n>0&&s5=="-") { System.out.print(s5+"1"); }else if(n>0) { System.out.print("+"+"1"); }else { System.out.print(s5+"1"); } } } }
源码分析:
该题可谓是目前所有题目集中难度最高的一个了。由于本人对于正则表达式不是很熟练,因此代码过于坑长。在源码中我们可以看到,我使用了一个单独的类来储存多元一次方程的每一项,从而对每一项分别进行求导并输出。首先我们输入一个一元多项时,根据正则表达式索引出有效的字符,并将其拆分成一个一个的项。使用replaceAll(“ ”,“”)来去除所有的多余空格,并将每一项导入类中。同时对输入的字符串进行单独配对,如果出现单独的字符零,便返回输入错误。在类中,使用多个pattern和matcher进行分辨配对。同时引入实数n,当配对成功时,n加一。以此来判断以求导向是否为第一项,并及时执行不同操作。对于其中的参数,我们同样使用this.来降低类与类之间的耦合度。很明显,本人的这个码源有着非常多的漏洞。正则表达式的使用过于频繁,很多情况可以其实可以概为一论,又有很一些情况没有考虑到,比如说大数,同时正常表达式过长,过于复杂,这些都是今后需要加强的地方。
三、踩坑心得
作为一个Java的初学者,未免会在这之中遇到一些问题,下面我就分享一些我在学习中的心得:
1.在Java中,‘+’有两种运算规则:
‘+’ 两端为数字则为数学加法运算。
实现字符串的连接,也可以实现字符串与其他数据类型的连接。
2.Java变量的命名规则如下:
可以以数字、字母、‘_’、'$'符组成
首字符不能以数字开头
中文可以作为变量名,但不提倡使用
Java大小写敏感,命名变量时要注意
不能使用Java保留字
Java变量名的定义应“见名知意”
3. Java中 this 和super 的异同:
简单的来说,this调用的是本类中的东西,super调用的是父类中的东西。
如果B类继承了A类,super对应A类,this对应B类。
四、改进建议
一个代码最重要的便是类与类之间的耦合度情况,每一个类实现一个功能,
题目集二和题目集三中,类中所需实现的功能还是过多,可以在原基础上在多加一些类进行多元处理,提升代码的专一性,可执行性。
对于一个代码而言,圈复杂度及其重要,这关系到一个代码的质量,
尽量少用if else,使用switch来减少程序的计算量,保证程序的稳定运行。
五、总结
对于此次题目集,我可以说学到了很多,也从一个Java白痴变成了一个初步了解Java的新人,学会了不同与c的类方法的使用,同时学会了正则表达式的使用,刚开始的时候,对于Java的学习并没有太过上心,题目集的完成时间较晚,但随着更深入的学习,我慢慢感受到了Java的魅力,并被它吸引着,我深刻的知道此时的我了解到的只是一些皮毛,未来的学习一定不会简单,但我不会畏惧,希望在未来我能够有更多的收获。
浙公网安备 33010602011771号