第一至三次作业总结
一、作业总结
第一次作业基本都是Java的基础语法使用,没有特别的知识点,面向对象也不够明显,和使用面向过程无太多区别,题量稍多但都是简单基础题目。
第二次作业主要是日期相关的操作,判断闰年,星期几,求一个日期前后若干天,题量适中,难度一般,主要出错一般是在特殊的日期,如跨年,闰年二月等,参照测试点说明可以很明确地知道错误所在。
第三次作业面向对象程度显著上升,三题都是要求设计一个类,难度也有所上升,主要涉及类的相关知识点
根据题目给出的类图就可以大概设计这个类并编写满足题目要求的测试程序,但是难度在于需要考虑到题目的边界值测试。
二、设计与分析
第一次作业
7-7 对多个整数进行排序
先从键盘输入一个整数n,n代表需要排序的整数数量,然后再从键盘输入n个整数,对这些数从小到大排序并输出。
输入格式:
先从键盘输入一个整数n,之后回车 再从键盘输入n个整数,整数之间用一个或多个空格分隔
输出格式:
按如下示例输出排序后的数据:The sorted numbers are:排序后的n个数,每个输出的整数之后有一个空格作为分隔符
无过多考虑可说,用数组接受输入后,采用排序算法排序即可
源码如下
import java.util.*;
class Main{
public static void main( String[] args ){
Scanner scanner = new Scanner(System.in);
int n=scanner.nextInt();
int a[] = new int[n];
for(int i=0;i<n;i++)
a[i]=scanner.nextInt();
Arrays.sort(a);
System.out.printf("The sorted numbers are:");
for(int i=0;i<n;i++)
System.out.printf("%d ",a[i]);
}
}
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.*;
class Main
{
public static void main( String[] args )
{
Scanner scanner = new Scanner(System.in);
double a,b,c;
a=scanner.nextDouble();
b=scanner.nextDouble();
c=scanner.nextDouble();
//System.out.printf("%f,%f,%f",a,b,c);
if((a>=1&&a<=200)&&(b>=1&&b<=200)&&(c>=1&&c<=200))
{
if(a>=b+c||b>=a+c||c>=a+b)
{
System.out.println("Not a triangle");
}
else
{
if(a==b&&a==c)
System.out.println("Equilateral triangle");
else if(a==b||b==c||a==c)
{
if(Math.abs(a*a+b*b-c*c)<=0.01||Math.abs(a*a+c*c-b*b)<=0.01||Math.abs(b*b+c*c-a*a)<=0.01)
System.out.println("Isosceles right-angled triangle");
else
System.out.println("Isosceles triangle");
}
else if(a*a+b*b==c*c||a*a+c*c==b*b||b*b+c*c==a*a)
System.out.println("Right-angled triangle");
else
System.out.println("General triangle");
}
}
else
{
System.out.println("Wrong Format");
}
}
}
第二次作业
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) {
@SuppressWarnings("resource")
Scanner input = new Scanner(System.in);
int year=input.nextInt();
int month=input.nextInt();
int day=input.nextInt();
if(checkInputValidity(year, month, day))
{
nextDate(year, month, day);
}
}
public static boolean isLeapYear(int year)
{
if((year%4==0&&year%100!=0)||year%400==0)
return true;
return false;
}//判断year是否为闰年,返回boolean类型
public static boolean checkInputValidity(int year,int month,int day)
{
int flag=1;
if(year<1820||year>2020||month<1||month>12||day<1||day>31)
{
System.out.println("Wrong Format");
flag=0;
}
else
{
if(month==2)
{
if(isLeapYear(year)&&day>29)
{
System.out.println("Wrong Format");
flag=0;
}
if(!isLeapYear(year)&&day>28)
{
System.out.println("Wrong Format");
flag=0;
}
}
if(month==4||month==6||month==9||month==11)
{
if(day==31)
{
System.out.println("Wrong Format");
flag=0;
}
}
}
if(flag==1)
return true;
else
return false;
}//判断输入日期是否合法,返回布尔值
public static void nextDate(int year,int month,int day)
{
int[]a= {0,31,28,31,30,31,30,31,31,30,31,30,31};
int[]b={0,31,29,31,30,31,30,31,31,30,31,30,31};
if(isLeapYear(year))
{
day+=1;
if(day>b[month])
{
day=1;
month+=1;
}
if(month==13)
{
year+=1;
month=1;
}
}
else
{
day+=1;
if(day>a[month])
{
day=1;
month+=1;
}
if(month==13)
{
year+=1;
month=1;
}
}
System.out.println("Next date is:"+year+"-"+month+"-"+day);
}//求输入日期的下一天
}
7-5 求前N天
输入年月日的值(均为整型数),同时输入一个取值范围在[-10,10] 之间的整型数n,输出该日期的前n天(当n > 0时)、该日期的后n天(当n<0时)。
其中年份取值范围为 [1820,2020] ,月份取值范围为[1,12] ,日期取值范围为[1,31] 。
注意:不允许使用Java中任何与日期有关的类或方法。
输入格式:
在一行中输入年月日的值以及n的值,可以用一个或多个空格或回车分隔。
输出格式:
当输入的年、月、日以及n的值非法时,输出“Wrong Format”;
当输入数据合法时,输出“n days ago is:年-月-日”
本题和前一题区别不大只是要求前后若干天,多考虑跨月时的情况,注意闰年二月的29天
源码如下
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
@SuppressWarnings("resource")
Scanner input = new Scanner(System.in);
int year=input.nextInt();
int month=input.nextInt();
int day=input.nextInt();
int pre=input.nextInt();
if(checkInputValidity(year, month, day))
{
nextDate(year, month, day,-pre);
}
}
public static boolean isLeapYear(int year)
{
if((year%4==0&&year%100!=0)||year%400==0)
return true;
return false;
}//判断year是否为闰年,返回boolean类型
public static boolean checkInputValidity(int year,int month,int day)
{
int flag=1;
if(year<1820||year>2020||month<1||month>12||day<1||day>31)
{
System.out.println("Wrong Format");
flag=0;
}
else
{
if(month==2)
{
if(isLeapYear(year)&&day>29)
{
System.out.println("Wrong Format");
flag=0;
}
if(!isLeapYear(year)&&day>28)
{
System.out.println("Wrong Format");
flag=0;
}
}
if(month==4||month==6||month==9||month==11)
{
if(day==31)
{
System.out.println("Wrong Format");
flag=0;
}
}
}
if(flag==1)
return true;
else
return false;
}//判断输入日期是否合法,返回布尔值
public static void nextDate(int year,int month,int day,int n)
{
int[]a= {31,31,28,31,30,31,30,31,31,30,31,30,31};
int[]b={31,31,29,31,30,31,30,31,31,30,31,30,31};
if(isLeapYear(year))
{
day+=n;
if(day>b[month])
{
day-=b[month];
month+=1;
}
if(day<=0)
{
month-=1;
day=b[month]+day;
}
if(month==13)
{
year+=1;
month=1;
}
if(month==0)
{
year-=1;
month=12;
}
}
else
{
day+=n;
if(day>a[month])
{
day-=a[month];
month+=1;
}
if(day<=0)
{
month-=1;
day=a[month]+day;
}
if(month==13)
{
year+=1;
month=1;
}
if(month==0)
{
year-=1;
month=12;
}
}
System.out.println(-n+" days ago is:"+year+"-"+month+"-"+day);
}//求输入日期的下一天
}
类图设计

第三次作业
7-2 定义日期类
定义一个类Date,包含三个私有属性年(year)、月(month)、日(day),均为整型数,其中:年份的合法取值范围为[1900,2000] ,月份合法取值范围为[1,12] ,日期合法取值范围为[1,31]
输入格式:
在一行内输入年月日的值,均为整型数,可以用一到多个空格或回车分隔。
输出格式:
当输入数据非法及输入日期不存在时,输出“Date Format is Wrong”;
当输入日期合法,输出下一天,格式如下:Next day is:年-月-日
本题按照题目所给类图设计,注意合法范围及输出格式即可
源码如下
import java.util.*;
class Date
{
private int year;
private int month;
private int day;
int[] mon_maxnum=new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31};
Date()
{
}
Date(int year,int month,int day)
{
this.year=year;
this.month=month;
this.day=day;
}
int getYear()
{
return this.year;
}
int getMonth()
{
return this.month;
}
int getDay()
{
return this.day;
}
void setYear(int year)
{
this.year=year;
}
void setMonth(int month)
{
this.month=month;
}
void setDay(int day)
{
this.day=day;
}
boolean isLeapYear(int year)
{
if((year%4==0&&year%100!=0)||year%400==0)
return true;
return false;
}
boolean checkInputValidity()
{
int flag=1;
if(year<1900||year>2000||month<1||month>12||day<1||day>31)
{
System.out.println("Date Format is Wrong");
flag=0;
}
else
{
if(month==2)
{
if(isLeapYear(year)&&day>29)
{
System.out.println("Date Format is Wrong");
flag=0;
}
if(!isLeapYear(year)&&day>28)
{
System.out.println("Date Format is Wrong");
flag=0;
}
}
if(month==4||month==6||month==9||month==11)
{
if(day==31)
{
System.out.println("Date Format is Wrong");
flag=0;
}
}
}
if(flag==1)
return true;
else
return false;
}
void getNextDate()
{
if(isLeapYear(year))
{
mon_maxnum[2]=29;
day+=1;
if(day>mon_maxnum[month])
{
day=1;
month+=1;
}
if(month==13)
{
year+=1;
month=1;
}
}
else
{
mon_maxnum[2]=28;
day+=1;
if(day>mon_maxnum[month])
{
day=1;
month+=1;
}
if(month==13)
{
year+=1;
month=1;
}
}
}
}
class Main
{
public static void main(String[] args)
{
@SuppressWarnings("resource")
Scanner input = new Scanner(System.in);
int year=input.nextInt();
int month=input.nextInt();
int day=input.nextInt();
Date date=new Date(year,month,day);
if(date.checkInputValidity())
{
date.getNextDate();
// System.out.println("Next day is:"+date.getYear()+"年-"+date.getMonth()+"月-"+date.getDay()+"日");
System.out.println("Next day is:"+date.getYear()+"-"+date.getMonth()+"-"+date.getDay());
}
}
}
7-3 一元多项式求导(类设计)
编写程序性,实现对简单多项式的导函数进行求解。
输入格式:
在一行内输入一个待计算导函数的表达式,以回车符结束。
输出格式:
如果输入表达式不符合上述表达式基本规则,则输出“Wrong Format”。
如果输入合法,则在一行内正常输出该表达式的导函数,注意以下几点: 结果不需要排序,也不需要化简;
当某一项为“0”时,则该项不需要显示,但如果整个导函数结果为“0”时,则显示为“0”;
当输出结果第一项系数符号为“+”时,不输出“+”;
当指数符号为“+”时,不输出“+”;
当指数值为“0”时,则不需要输出“x^0”,只需要输出其系数即可。
输出格式见输入输出示例。
本题难点在于,检验输入是否为一个合法的一元多项式并要求考虑到各种情况并做出处理,考虑使用了正则检测输入合法性
类图设计如下

源码如下
import java.math.BigInteger;
import java.util.Scanner;
import java.util.LinkedList;
class DvForString {
private static LinkedList<String> item;//存储各项,此题并不需要
private static String sign,number,regex,regex1,regex2,regex3,concat,concatend,specialnum,end;//各项正则
//静态区,字符串
static {
//静态区只在类被加载时被执行一次
item=new LinkedList<>();
sign="(?:[+|-])";
number="(?:([1-9](\\s*\\d*\\s*)*))";
//全是常数项时的特判
specialnum="((?:(\\s*([+|-]?[1-9]+\\s*\\d*)\\s*))*)";
//带x项,允许系数中间内有空格
//有不为0的系数和指数
regex="(?:(([1-9](\\s*\\d*\\s*)*)\\s*\\*\\s*x\\s*\\^\\s*[+|-]?\\s*([1-9](\\s*\\d*\\s*)*)))";
//x只有指数
regex1="(?:(x\\s*\\^\\s*[+|-]?\\s*([1-9](\\s*\\d*\\s*)*)))";
//x只有系数
regex2="(?:(([1-9](\\s*\\d*\\s*)*)\\s*\\*\\s*x))";
//x前面系数,指数都没有
regex3="(?:x)";
concat="("+regex+"|"+regex1+"|"+regex2+"|"+regex3+")";
//数字和带x项或在一起构成多项式中的一项
concatend="("+concat+"|"+number+")";
//多项式表达式 ,首项可以无+,-, 后续项必须有
end="(?:("+"\\s*"+sign+"?\\s*"+concatend+"(?:\\s*"+sign+"\\s*"+concatend+"\\s*)*"+"))";
}
//Polynomial 多项式
private String Polynomial=null;
public LinkedList<String> getItem() {
return item;
}
//无参构造
public DvForString(){}
//有参构造,可以直接通过字符串数组名赋值另一个相同大小和类型的数组
public DvForString(String polynomial) {
this.Polynomial = polynomial;
}
//对私有变量获取和,赋值的方法
public String getPolynomial() {
return Polynomial;
}
public void setPolynomial(String polynomial) {
this.Polynomial = polynomial;
}
//合法性检验
private boolean isLegal() {
boolean flag=true;
String s=Polynomial;
//全常数检验
if(s.matches(specialnum))
return true;
//复杂多项式检验
if(!s.matches(end)) flag=false;
return flag;
}
//打印合法输入中每一项
public void printEveryElement() {
System.out.println();
if(isLegal()) { for(String e: item) System.out.println(e);}
else System.out.println("Wrong Format");
}
//打印
public void print() {
if(isLegal()) printLegal();//合法结果打印
else printNotLegal();//不合法结果打印
}
//打印不合法输出
private void printNotLegal() {
System.out.println("Wrong Format");
}
//打印合法输出
private void printLegal() {
//拷贝一份给字符串s
String s=Polynomial;
s=s.replace(" ","");
char[] t=s.toCharArray();
for(int i=0;i<s.length()-1;i++)
if(t[i]=='^'&&t[i+1]=='-') t[i+1]='#';
//直接通过tostring转换字符数组会出错,所以一个个字符拼接
String s1="";
for(int i=0;i<t.length;i++)
s1=s1+t[i];
//再来整体替换-
s1=s1.replace("^+","^");
s1=s1.replace("-","+-");
//如果+出现在第一个位置会报异常,要用\\+
String [] id=s1.split("\\+");
//加号输出标记
int flag=0;
//无项时输出标记,标记若最终为0,最后输出0
int lazy=0;
//所有常数直接打印不需要特意放+,带x项,对于大于0项,前面有其他项要打印出来
for(String e :id) {
//切开后对每个元素进行分析处理,#要替换成-
e=e.replace("#","-");
if(e!=null) item.addLast(e);
int start=e.indexOf("x");
int mid=e.indexOf("*");
int end=e.indexOf("^");
//x,^都有
if(start!=-1&&end!=-1) {
//系数不为1,存在*
if(mid!=-1) {
BigInteger pro=new BigInteger(e.substring(0,mid));
BigInteger pos=new BigInteger(e.substring(end+1,e.length()));
BigInteger xishu=pro.multiply(pos);//乘法
BigInteger zhishu=pos.subtract(new BigInteger(1+""));//减法
if(zhishu.equals(new BigInteger(0+""))) System.out.print(xishu);
else {
if(xishu.equals(new BigInteger(1+""))) System.out.print("x^"+zhishu);
else if(xishu.equals(new BigInteger(-1+"")))System.out.print("-x^"+zhishu);
else {
if( xishu.compareTo(new BigInteger(0+""))>0)
if(flag==1) System.out.print("+");
System.out.print(xishu+"*x^"+zhishu);
}
}
lazy=1;
if(flag==0) flag=1;
}
//没有*,系数为负
else {
if(e.charAt(0)=='-') {
BigInteger pos=new BigInteger(e.substring(end+1,e.length()));
BigInteger xishu=pos.multiply(new BigInteger(-1+""));//乘法
BigInteger zhishu=pos.subtract(new BigInteger(1+""));//减法
if(zhishu.equals(new BigInteger(0+""))) System.out.print(xishu);
else {
if(xishu.equals(new BigInteger(1+""))) System.out.print("x^"+zhishu);
else if(xishu.equals(new BigInteger(-1+"")))System.out.print("-x^"+zhishu);
else {
if( xishu.compareTo(new BigInteger(0+""))>0)
if(flag==1) System.out.print("+");
System.out.print(xishu+"*x^"+zhishu);
}
}
}
//没*,系数不为负
else {
BigInteger pos=new BigInteger(e.substring(end+1,e.length()));
BigInteger xishu=pos.multiply(new BigInteger(1+""));//乘法
BigInteger zhishu=pos.subtract(new BigInteger(1+""));//减法
if(zhishu.equals(new BigInteger(0+""))) System.out.print(xishu);
else {
if(xishu.equals(new BigInteger(1+""))) System.out.print("x^"+zhishu);
else if(xishu.equals(new BigInteger(-1+"")))System.out.print("-x^"+zhishu);
else {
if( xishu.compareTo(new BigInteger(0+""))>0)
if(flag==1) System.out.print("+");
System.out.print(xishu+"*x^"+zhishu);
}
}
}
lazy=1;
if(flag==0) flag=1;
}
}//^,x都存在的分界线
//有x,没有指数
else if(start!=-1) {
//有*
if(mid!=-1) {
BigInteger num=new BigInteger(e.substring(0, mid));
// if(num.compareTo(new BigInteger(0+""))>0) if(flag==1) System.out.print("+");
System.out.print(num);
}
//没有*
else {
BigInteger num=null;
if(e.charAt(0)=='x') num=new BigInteger("1");
else if(e.charAt(0)=='-') num=new BigInteger("-1");
else
num=new BigInteger(e.substring(0, start));
// if(num.compareTo(new BigInteger(0+""))>0) if(flag==1) System.out.print("+");
System.out.print(num);
}
lazy=1;
if(flag==0) flag=1;
}
//常数
else
System.out.print("");
}//大for结尾
if(lazy==0) System.out.println(0);
}
}
//Derivation 求导
public class Main {
@SuppressWarnings("resource")
public static void main(String[] args){
Scanner in=new Scanner(System.in);
String temp=in.nextLine();
DvForString dv=new DvForString();
dv.setPolynomial(temp);//预处理输入的字符串
dv.print(); //根据合法性作出不同输出
// System.out.println();
// dv.printEveryElement();
}
}
复杂度参考


三、踩坑心得
第一次作业7-8,在判断直角时,直接使用a^2 + b^2 =c^2导致判断不出是直角,改进为两者绝对值相差小于0.01判断为直角
第二次作业两题都类似,需要注意到闰年二月的特殊性以及输出的格式
第三次作业7-2:同之前的日期相关题目,考虑问题要注意特殊点。7-3:对于负数的系数没有考虑完全而产生错误,对于负系数和指数还有零系数都是要考虑到的问题,题目自身测试点也有所问题一次正项求导后不输入+。
踩坑很正常,但一定要自己纠错,在纠错中有所进步。
四、改进建议
第三次作业的7-3,圈复杂度略高,需要改进,拆分为多个类,分工实现功能。
五、总结
通过这三次作业,我了解了Java基础的语法使用,强化了我的面对对象思维,先设计类,再按编程语法翻译成代码。其次便是对正则表达式的使用,正则的使用简化了非常多的验证操作

浙公网安备 33010602011771号