Blog作业01
一、前言
第一次作业是对一些简单的if语句、for循环以及一维数组的使用;第二次作业前两题是对数字和数组的操作,后三题主要是求日期,用到了Boolean类型,并且从这开始运用方法来解决一些简单问题;第三次作业开始用到了类以及对类操作的一些方法(如set、get),理解类的封装性,在第三题运用到了BigInteger类型对大数据进行操作,还有replace、split、contains、equals等对字符串操作的函数。
总的来说,前两次题目量较第三次多,但第三次题目集与前两次相比难度较大,特别是对一元多项式求导。
二、设计与分析
第一次题目集7-8:
7-8题是对用户输入的三角形的三个边长来判读构成的三角形是什么三
角形。

1.对用户输入的边长用double型变量来存,先对输入合法性以及三个边长
是否能构成三角形进行判断,若可以构成三角形再来判断是什么三角形。
代码:if(a<1||a>200||b<1||b>200||c<1||c>200)
if(a+b<=c||b+c<=a||a+c<=b||a-b>=c||b-c>=a||a-c>=b||c-a>=b||c-b>=a||b-a>=c)
2.等边三角形(Equilateral triangle):三条边相等;
代码:if(a==b&&a==c&&b==c)
3.等腰直角三角形(Isosceles right-angled triangle):任意两边相等且第三条边边长的平方与相等两边边长平方和之差小于1*10^-5;
代码:if((a==b&&((a*a+b*b-c*c)<1e-5)||(a==c&&(a*a+c*c-b*b)
<1e-5)||((c*c+b*b-a*a)<1e-5)))
4.等腰三角形(Isosceles triangle):任意两条边相等;
代码:if((a==b)||(a==c)||(c==b))
6.直角三角形(Right-angled triangle):两边平方和与第三边之差小于1*10^-5;
代码:if(((a*a+b*b-c*c)<1e-5)||((a*a+c*c-b*b)<1e-5)
||((c*c+b*b-a*a)<1e-5))
7.若都不是以上特殊三角形则输出普通三角形(General triangle);
8.每次判断结束System.exit(0);则不需要继续下面的判断。

问题:在计算是否是直角三角形时,错误的以为勾股定理必须相等,后来在网上查找后,发现直角边的平方和与斜边平方之差只要小于1*10^-5就可以认为是直角三角形,因为在计算平方时会出现一条边有根号时才能满足勾股定理,所以会有误差。
小结:题目较简单,但代码中都是if语句,可以用switch语句来代替,使代码看起来更简洁。
第二次题目集7-4:
7-4题是判断用户输入的日期的下一天。

1.先判断用户输入的日期是否合法;
年份的合法取值范围为[1820,2020] ,月份合法取值范围为[1,12] ,日期合法取值范围为[1,31] 。
代码:public static boolean checkInputValidity(int year,int month,int day) {
boolean key = true;
if((year<1820||year>2020)||(month<1||month>12) ||(month==1||month==3||month==5||month==7||month==8||
month==10||month==12)&&(day<1||day>31)||
((month==4||month==6||month==9||month==11)&&(day<1||day>30))
||(isLeapYear(year)&&month==2&&(day<1||day>29))
||(!isLeapYear(year)&&month==2&&(day<1||day>28)))
key = false;
return key;
}
2.判断是否为闰年;
如果输入的年份除以400等于零或除以4等于零但除以100不等于零。
代码:public static boolean isLeapYear(int year){
boolean key = false;
if(year%400 == 0||(year%4 == 0&&year%100 != 0))
key =true;
return key;
}
3.根据是不是闰年来确定下一天日期;
需要注意的是下一天可能会跨年、跨月,还要注意2月的天数。
代码:
4.最后按格式输出下一天日期;
代码:System.out.println("Next date is:" + year + "-" + month + "-" + newday);

小结:本题需要写判断是否为闰年、判断输入合法性以及求下一天三个方法。
其中求下一天需要想到各种情况,容易出错的是闰年和下一天下一个月的第一天。总体来说不是很复杂。
第二次题目集7-5:
本题是求用户输入的日期的前n天,

1.判断用户输入合法性;构造返回Boolean类型的方法;
代码:public static boolean checkInputValidity(int year,int month,int day,int n) {
boolean key = true;
if((year<1820||year>2020)||(month<1||month>12)
||((month==1||month==3||month==5||month==7||month==8
||month==10||month==12)&&(day<1||day>31))
||((month==4||month==6||month==9||month==11)&&(day<1
||day>30))
||(isLeapYear(year)&&month==2&&(day<1||day>29))
||(!isLeapYear(year)&&month==2&&(day<1||day>28))
||(n<-10||n>10))
key = false;
return key;
}
2.判断输入的年份是否为闰年;构造返回Boolean类型的方法;
代码:public static boolean isLeapYear(int year){
boolean key = false;
if(year%400 == 0||(year%4 == 0&&year%100 != 0))
key =true;
return key;
}
3.求前n天;
①前n天可能是下一年或上一年。
当月份是12且日期减n大于31时,说明前n天为下一年;
当月份是1且日期减n小于0时,说明前n天为上一年;
if(month == 12&&(day-n) > 31) {
year++;
month = 1;
newday = day - n -31;
System.out.println(n + " days ago is:" + year + "-" + month + "-" + newday);
System.exit(0);
}
if((day - n) <= 0&&month == 1){
year--;
month = 12;
newday = newday - n + 31;
}
②一个月是31天的情况。
日期减你n大于0且日期小于21时,前n天大于输入的日期减n再加上上一个月的天数。


③一个月是30天的情况。
当天数小于19且天数减n大于0时,日期等于天数减n;小于0且不是3月时日期等于天数减n再加上上一个月的天数。
当天数大于20时且天数减n大于30时,等于天数减n再减本月的天数;小于30时,等于天数减n。

④当月份为2月时;


⑤最后按格式输出前n天的日期;
代码:
System.out.println(n + " days ago is:" + year + "-" + month + "-" + newday);

小结:本题比7-4求下一天要复杂,代码的复杂度较高,只因为代码中使用了很多嵌套的if语句,有很多重复的地方,在后续的学习中尽量降低代码的复杂度。
第三次题目集7-2:
本题也是求输入的日期的下一天,但在第二次题目集7-4的基础上增加了用类的要求。

1.定义类Date,私有属性有年份、月份和日期。
private int year;
private int month;
private int day;
创建一个对象Date date = new Date();在类中构造一个方法set来存年份、月份和日期。date.setDate(year,month,day);
在类中构造get方法来获取私有值年份、月份和日期。
public int getyear(){
return year;
}
public int getmonth(){
return month;
}
public int getday(){
return day;
}
2.判断输入合法性;
代码: public boolean checkInputValidity(){
boolean key = true;
if((year<1900||year>2000)||(month<1||month>12)||(month==1||month==3||month==5||
month==7||month==8||month==10||month==12)&&(day<1||day>31)
||((month==4||month==6||month==9||month==11)&&(day<1||day>30))
||(isLeapYear()&&month==2&&(day<1||day>29))
||(!isLeapYear()&&month==2&&(day<1||day>28)))
key = false;
return key;
}
if(!date.checkInputValidity()) {
System.out.println("Date Format is Wrong");
System.exit(0);
}
3.判断年份是否为闰年;
代码:public boolean isLeapYear() {
boolean key = false;
if(year%400==0||(year%100!=0&&year%4==0))
key = true;
return key;
}
4.求下一天;
5.最后按格式输出下一天;
代码:System.out.println("Next day is:" + date.getyear() + "-" + date.getmonth() + "-" + date.getday());
小结:这题和题目集二7-4题目几乎一样,只是加上了用类来写的要求,容易出错的地方在类中定义的变量为私有的,另外不能从主函数中直接传入类中。
第三次题目集7-3:
本体为一元多项式求导,这题是所有题目中最难的题目,用到的很多方法、函数都是没有学过的。用户输入一个一元多项式,程序输出求导后的多项式。

1.构造类Qiudao,私有属性有用户输入的多项式,以及求导后的多项式;

创建对象:Qiudao qiudao = new Qiudao();
在类中构造set方法来存储多项式:
qiudao.setA(a);
public void setA(String a){
this.a = a;
}
2.判断用户输入的合法性;多项式中存在系数为0和指数为0的情况都为不合法;
代码:public boolean checkInputValidity() {
boolean key2 = true;
if(a.contains("+0*")||a.contains("-0*")
||a.contains("x^0")||a=="")
key2 = false;
return key2;
}
3.判断输入的多项式中是否有x,也就是多项式是否全为常数;
代码:public boolean constant() {
boolean key1 = true;
if(!a.contains("x"))
key1 = false;
return key1;
}
如果多项书中没有x,求导后则为0,直接输出0。
代码:if(!qiudao.constant()){
System.out.print(0);
System.exit(0);
}
4.如果多项式合法且含有x,则进行求导;
①先将多项式中的空格去掉;将‘-’换为’+-‘;将’^+‘换为’^‘;
代码:a = a.replaceAll(" ", "");
a = a.replace("-", "+-");
a = a.replace("^+", "^");
②将多项式从’+‘处将多项式断开,并存到一个字符串数组中;
若存在常数项,则先将常数项去除;
代码:if(a.charAt(0)=='+') {
b = a.substring(1,a.length());
newa = b.split("\\+");
}
else
newa = a.split("\\+");//把字符串从'+'处断开,并存到字符串数组里
int length = newa.length;
for(int i = 0;i < length;i++) {
if(!newa[i].contains("x")) {
for(int j = i;j < length-1;j++)
newa[j] = newa[j+1];
length--;
i--;
}
}//除去最初多项式中常项
③定义一个字符串二维数组,将字符串数组中每一项的系数和指数取出;
如果有’*‘,取字符串第一位到’*‘为系数,没有则系数为1;
如果有’^‘,取字符串’^‘到字符串最后一位为指数,没有则系指数为1;
代码:String[][] num = new String [length][2];
for(int i = 0;i < length;i++) {
c = newa[i];
if(c.contains("*"))
num[i][0] = c.substring(0,c.indexOf("*"));
else
num[i][0] = c.substring(0,c.indexOf("x")) + "1";
if(c.contains("^"))
num[i][1] = c.substring(c.indexOf("^")+1,
c.length());
else
num[i][1] = "1";
}//取出每项的系数和次数
④将系数和指数转换为大数据BigInteger型,然后将求导后的系数和指数重新存到二维数组中;
代码:for(int j = 0;j < length;j++) {
BigInteger o = new BigInteger("1");
BigInteger p = new BigInteger(num[j][0]);
BigInteger q = new BigInteger(num[j][1]);
num[j][0] = String.valueOf(p.multiply(q));
num[j][1] = String.valueOf(q.subtract(o));
}//存储求导后的系数和次数
⑤判断系数是否为正数,若为正数,则在系数前加上’+‘;
代码:for(int i = 0;i < length;i++) {
if(num[i][0].charAt(0)!='-'&&!num[i][1].equals("0"))
num[i][0] = "+" + num[i][0];
}//如果系数为正数在系数和次数前面加上'+'
⑥将求导后多项式重新整理存到一个字符串中;
若指数为1,该项类型为’*x‘;
若系数为1且指数不为0,该项类型为’x^‘;
若系数为-1且指数不为0,该项类型为’-x^‘;
若以上都不是,该项类型为’*x^‘;
代码:for(int i = 0;i < length;i++) {
if(num[i][1].equals("1"))
d = d + num[i][0] + "*x";
else if((num[i][0].equals("+1"))&&!num[i][1].equals("0"))
d = d + "x" + "^" + num[i][1] ;
else if((num[i][0].equals("-1"))&&!num[i][1].equals("0"))
d = d + "-x" + "^" + num[i][1] ;
else
d = d + num[i][0] + "*x" + "^" + num[i][1] ;
}
⑦最后,输出求导后正确多项式;
代码:System.out.print(qiudao.getDerivation());
d = d.replace("*x^0","");
if(d.charAt(0)=='+')
d = d.substring(1,d.length());//如果求导后第一项
系数为正,删去第一项系数前'+'

小结:本体比前面的题目要复杂,用到的一些新方法也比较多,比如replace、split、BigInteger,另外本题应该用正则表达式来写会简单一些,但是这次写题时还没有学会,就使用了字符串的一些判断函数,在以后的学习中学会正则表达式让代码更简单;通过这个题目也学会了一些新的方法来处理字符串。
三、测试与错误分析
第一次题目集7-8:
测试1:
输入:3 4 5
输出:Right-angled triangle
测试2:
输入:300 2 5
输出:Wrong Format

测试3:
输入:1 1 6
输出:Not a triangle

错误:
本题出现的一个错误是在求直角三角形时没有想到勾股定理会存在误差,我写的是a^2+b^2=c^2;而正确的应该是 a^2+b^2-c^2<1*10^-5;
第二次题目集7-4:
测试1:
输入:2020 3 10
输出:Next date is:2020-3-11

测试2:
输入:2025 3 10
输出:Wrong Format

测试3:
输入:2000 12 31
输出:Next date is:2001-1-1

错误:
下一天是下一年的情况没有考虑到,还有就是1月份的下一天是2月的情况。
第二次题目集7-5:
测试1:
输入:2018 6 19 8
输出:8 days ago is:2018-6-11

测试2:
输入:2018 6 19 -8
输出:-8 days ago is:2018-6-27

测试3:
输入:2000 12 28 -6
输出:-6 days ago is:2001-1-3

测试4:
输入:2000 1 1 6
输出:6 days ago is:1999-12-26

错误:
上一天是上一年的情况没有考虑到,n天后为下一个月或上一个月时,天数上是加还是减上一月或下一个月天数总是会弄错。
第三次题目集7-2:
测试1:
输入:1912 12 25
输出:Next day is:1912-12-26

测试2:
输入:2001 2 30
输出:Date Format is Wrong

测试3:
输入:2000 1 31
输出:Next day is:2000-2-1

错误:
这题与第二次题目集7-4题目一样,所以这次没有出现错误。
第三次题目集7-3:
测试1:
输入:-2* x^-2+ 5*x^12-4*x+ 12
输出:4*x^-3+60*x^11-4

测试2:
输入:2*x^6-0*x^7+5
输出:Wrong Format

测试3:
输入:x^-5+6*x^7-1200*x^-1000+54468799958488*x^-925546
输出:-5*x^-6+42*x^6+1200000*x^-1001-
50413379926378734448*x^-925547

测试4:
输入:1+5+8+66
输出:0

错误:
1.第一次处理大数据时,想着用字符串来存,让后转为整形乘完后在存到字符串中,但发现大数据超过了整形的范围;在网上查阅后发现可以用BigInteger类型来存大数据,先将字符串转为BigInteger,做完乘积后在转为字符串,这样就可以解决超出整形范围的问题。
2.没有考虑到系数和指数在求导后为1时不能输出1,可以省略。
四、总结
从第一次作业到第三次作业,难度逐渐上升,所需的知识也越来越多。第一次作业较简单,学到了在判断直角三角形时,用勾股定理不能直接等于,而是两直角边平方和与斜边平方之差小于1*10^-5;第二次作业开始用类和方法,学会了怎么把两个数组组合并排序、怎么去使用boolean变量以及对IP地址转换等。第三次作业难度明显上升,最难的是一元多项式求导,学会了怎么去创建类与对象,并会使用类的构造方法和set、get等方法;理解了类的封装性;通过一元多项式求导我学会了一些对字符串操作的一些方法,如replace、split。还学会了当数字很大时,超过了整形的范围可以用BigInteger类型变量来存储。
通过这三次作业我觉得我还需要学习一下正则表达式,正则表达式在对字符串处理上很烦便,代码也比传统方法简洁。
对教师的上课方式,我认为有点太快了,很容易跟不上,希望老师可以讲慢一点。

浙公网安备 33010602011771号