JAVA-PTA题目集与实验五总结
通过10-16周对JAVA这门编程语言的学习以及PTA题目集的完成,又有所收获,在此对自己近期PTA题目集的完成情况做一个总结。
前言:
(1)PTA大作业六的题目有电信计费系列-座机计费、多态测试。多态测试难度不大,主要考察容器、接口、多态知识的掌握。电信计费系列-座机计费难度较大些,主要是要看得懂类图,认真分析各类之间的联系,使用正则表达式判断格式是否正确。
(2)PTA大作业七,难度相较题目集PTA大作业六有了一定提升。7-2、7-3知识点上相对于PTA大作业六没有太大的变化,但是对容器类的功能的考察更为深入,涉及了更多关于容器的用法。7-1电信计费系列2-手机+座机计费对手机和座机号码的筛选和区别有了一定需求,主要是要对正则表达式加以修改,然后记录拨打电话所在区域,根据手机和座机号码的不同,分别以不同规则计费。
(3)PTA大作业八相对简单。7-1电信计费系列3-短信计费只需要在前两题的基础上新添上判断短信格式的正则表达式和对应的计费方式类即可,7-2主要考察了内部类的用法,7-3主要考察多态的用法。
(4)实验五,通过javaFX对农夫过河游戏代码进行修改,因为初学javaFX让我感觉到十分的困难,和c语言课设时的感受一样,不过慢慢学习下来还是收获了许多,有了初步的了解。设计的知识点有
JavaFX的基本原理和基本组件、应用JavaFX组件进行界面设计、Java的事件驱动机制、lambda表达式、掌握shape形状类的使用。
接下来是各题目的设计与分析、踩坑心得与改进建议
一、7-1 电信计费系列1-座机计费
设计与分析
通过sourceMonitor的生成报表内容获取代码圈复杂度
圈复杂度为19

设计:1.本题我先写出一个正则表达式判断用户是否能开户成功,并将符合正则表达式的号码存入user类中,并判断是否重复开户。
2.然后再用正则表达判断通话记录中号码与时间是否输入正确,若正确通过区域的不同将加入user中的callRecord类中对应地区的通话记录。
3.在计费规则中分别计算不同拨打地区的费用总和在一起则是通话费用。
分析:
1.正则表达式判断格式,并忽略重复输入的用户,并将对应的通话记录存入容器中。
while(!s.equals("end"))
{
if(s.matches("^u-[0][0-9]{9,11} 0$"))
{
a=s.length();
int flag=1;
x=s.substring(2,a-2);
for(int i=0;i<count;i++)
if(x.equals(u[i].getNumber()))
flag=0;
if(flag==1)
{
u[count].setNumber(x);
count++;
}
}
else if(s.matches("^t-[0][0-9]{9,11} [0][0-9]{9,11} [\\d]{4}[.]([\\d]|([1][0-2]))[.]([\\d]|[1-2][\\d]|3[0-1]) ([0-1][\\d]|2[0-3])[:]([0-5][\\d])[:]([0-5][\\d]) [\\d]{4}[.]([\\d]|([1][0-2]))[.]([\\d]|[1-2][\\d]|3[0-1]) ([0-1][\\d]|2[0-3])[:]([0-5][\\d])[:]([0-5][\\d])$"))
{
String[] b=s.split("\\s+");
x=b[0].substring(2,b[0].length());
for(int i=0;i<count;i++)
{
if(x.equals(u[i].getNumber()))
{
CallRecord callrecord=new CallRecord(b[0],b[1]);
String s1=b[2]+" "+b[3];
String s2=b[4]+" "+b[5];
Date d1 = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss").parse(s1);
Date d2 = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss").parse(s2);
callrecord.setStartTime(d1);
callrecord.setEndTime(d2);
if(x.substring(0,4).equals("0791")&&b[1].substring(0,4).equals("0791"))
u[i].getUserRecords().addCallingInCityRecords(callrecord);
else if(x.substring(0,4).matches("([0][7][9][0-9])|([0][7][0][1])")&&b[1].substring(0,4).matches("([0][7][9][0-9])|([0][7][0][1])"))
u[i].getUserRecords().addCallingInProvinceRecords(callrecord);
else
u[i].getUserRecords().addCallingInLandRecords(callrecord);
}
}
}
s=in.nextLine();
}
2、不同地区对应的计费规则
class LandPhoneInCityRule extends CallChargeRule{
double calCost(ArrayList<CallRecord> callRecords) {
double sum=0;
for (CallRecord c :callRecords)
{
long diff=Math.abs(c.getStartTime().getTime() -c.getEndTime().getTime());
if(diff%(1000*60)>0)
diff=diff/(1000*60)+1;
else
diff=diff/(1000*60);
sum+=diff;
}
return sum*0.1;
}
}
class LandPhoneInProvinceRule extends CallChargeRule{
double calCost(ArrayList<CallRecord> callRecords) {
double sum=0;
for (CallRecord c :callRecords)
{
long diff=Math.abs(c.getStartTime().getTime() -c.getEndTime().getTime());
if(diff%(1000*60)>0)
diff=diff/(1000*60)+1;
else
diff=diff/(1000*60);
sum+=diff;
}
return sum*0.3;
}
}
class LandPhoneInLandRule extends CallChargeRule{
double calCost(ArrayList<CallRecord> callRecords) {
double sum=0;
for (CallRecord c :callRecords)
{
long diff=Math.abs(c.getStartTime().getTime() -c.getEndTime().getTime());
if(diff%(1000*60)>0)
diff=diff/(1000*60)+1;
else
diff=diff/(1000*60);
sum+=diff;
}
return sum*0.6;
}
}
踩坑心得![]()
1、 当时间不为整数有余时需要加一,不然答案会出错。

2、正则表达式时间需要考虑只有1-12月份,且有一月30、31天的区别。
3、需要判断是否重复开户。
4、
该测试点我对区域码判断错误导致一开始时一直错误,区域码还可以是三位数。
改进建议
通过sourceMonitor的生成报表内容中可以看出圈复杂度为19,则表示代码中的if语句使用过多,不太易懂,还可再简洁些。通过不同的方法完成功能的实现,也可以使代码更易读、简洁。以及计费处不太方便较为麻烦,可以继续改进。
二、电信计费系列2-手机+座机计费
设计与分析
圈复杂度40

设计:1.先判断开户格式是否符合座机或手机号码,存入user类中。
2.通过通话记录获取所在的区域编码。
3.然后新加area的方法判断区域编码所在区域。
4.通过计费规则chargerule计算。
5、User类为储存创建用户账号的类,UserRecords类为储存用户打电话与接电话信息的类,ChargeMode及其子类用于实现计费,其中所含有的ChargeRule及其子类用于计算规则
分析:
1.area判断区域方法
public static String area(String s) {
if(s.equals("0791"))
return "市内";
else if(s.matches("([0][7][9][0-9])|([0][7][0][1])"))
return "省内";
else
return "省外";
}
2.关于手机计费和座机计费的区分
class LandPhoneInCityRule extends CallChargeRule{
double calCost(ArrayList<CallRecord> callRecords) {
double sum=0;
for (CallRecord c :callRecords)
{
long diff=Math.abs(c.getStartTime().getTime() -c.getEndTime().getTime());
if(diff%(1000*60)>0)
diff=diff/(1000*60)+1;
else
diff=diff/(1000*60);
if(c.getCallingNumber().charAt(0)=='0')
{
if(c.getAnswerAddressAreaCode().equals("市内"))
sum+=diff*0.1;
else if(c.getAnswerAddressAreaCode().equals("省内"))
sum+=diff*0.3;
else
sum+=diff*0.6;
}
else if(c.getCallingNumber().charAt(0)=='1')
{
if(c.getAnswerAddressAreaCode().equals("市内"))
sum+=diff*0.1;
else if(c.getAnswerAddressAreaCode().equals("省内"))
sum+=diff*0.2;
else
sum+=diff*0.3;
}
}
return sum;
}
}
踩坑心得
1、当手机号码在省外接听时,需要另外判断,与拨打电话同时判断则会出现重复计入通话记录的情况。
2、0701也是省内区域,导致部分测试点开始时困扰了我许久。
改进建议
从圈复杂度40上看,代码依旧是由众多if语句完成,这使代码的可读性及效率变低。当时对于电话计费的规则不太熟悉,很多地方为了完成计费没有太认真的思考,比如记录拨打与接听电话同时存在的通话记录,使用了两个for循环区分开,但使代码复杂了很多,也出现了很多bug需要修改。进一步接触了抽象类的使用。
三、电信计费系列3-短信计费
设计与分析
圈复杂度44

设计:
1.开户与前两题相同。
2.当记录由m开头时,判断短信是否符合正则表达式。
3.进入短信计费规则计算费用。
4.User类为储存创建用户账号的类,UserRecords类为储存用户打电话与接电话信息的类,ChargeMode及其子类用于实现计费,其中所含有的ChargeRule及其子类用于计算规则
分析:
1.正则表达式判断短信记录
if(s.matches("^m-[0-9]{11} [0-9]{11} [\\w\\d ,.]+$"))
{
String[] b=s.split("\\s+");
x=b[0].substring(2,b[0].length());
a=s.length();
for(int i=0;i<count;i++)
{
MessageRecord messageRecords;
if(x.equals(u[i].getNumber()))
{
x1=s.substring(26,a);
messageRecords=new MessageRecord(x1);
u[i].getUserRecords().addSendMessageRecords(messageRecords);
}
}
}
2.短信计费规则
class SendMessageRule extends MessageRule{
double calCost(ArrayList<MessageRecord> messageRecords) {
double sum=0;
int count=0;
for(MessageRecord m:messageRecords)
{
if(m.getMessage().length()>10)
{
if((double)m.getMessage().length()/10>(int)m.getMessage().length()/10)
count+=m.getMessage().length()/10+1;
else
count+=m.getMessage().length()/10;
}
else
count+=1;
}
sum=count;
if(count<=3)
sum=sum*0.1;
else if(count>3&&count<=5)
sum=0.1*3+(sum-3)*0.2;
else
sum=0.7+(sum-5)*0.3;
return sum;
}
}
踩坑心得
1、不能用以空格为分割字符串数组,因为短信中也有空格字符,这使答案出现了错误。
2、短信计费时如果字符长度不是10的倍数,有余数则需要加一算作一条短信。
改进建议
圈复杂度为44则表明前面题目代码较为复杂的问题仍没有解决。正则表达式解决则省去了判断格式正误的一大串代码,可这还有很长的路要走,正则表达式需要更加深入地学习才能更好地应用,一个非常值得我们去学习的知识点。完善逻辑,使代码的效率提高,而且易懂。
四、农夫过河
设计与分析
最高圈复杂度为46

设计:
农夫过河游戏的代码,将用户界面改为图形界面。我将Main类中添加了Start方法用来做游戏界面,给游戏角色分别加上对应的图片效果,然后在Game类中对通过角色所在地点移动图片位置。最后判断游戏胜负并输出。
分析:
通过新建Image对象获取图片的位置,给农夫过河游戏中角色添加上图片更加生动,然后liy用setTranslate方法对x和y坐标进行移动实现过河。在主页面中通过对按钮点击,从而进入游戏的内部运行规则中,然后对Group进行修改后返回结点,进行show()。
踩坑心得
1、在Game类中修改结点,需要将void play()方法改为Group play()方法,并返回root结点,这样才能修改场景的结点。不然动画无法行动,只能停留在初始界面。
2、在进行图片操作前需要判断游戏是否结束,使按钮操作是否继续进行。
改进建议
我初步了解到了button、image、line等的用法,对javaFX有了初步的了解。期间又遇到了些问题,比如转换页面中可以使用setRoot更改结点就行或是关闭当前的舞台,新建一个舞台并展示。总的来说,虽然javaFX初学以来有些困难,但是通过上网查阅资料还是能对问题进行解决的。了解JavaFX的基本原理和基本组件,初步应用JavaFX组件进行界面设计,了解Java的事件驱动机制、lambda表达式和shape形状类的使用。
总结
1.在这几次作业中,我发现自己代码的逻辑性不够好,从圈复杂度高这一特点可以看出存在太多不必要的代码了。逻辑不清晰导致代码冗长,代码质量不高。
2.通过电信计费系列的题目我对正则表达式这一知识点的了解更加的深入了,对其基本的语法有了一定认知,希望之后的学习中能更深入的了解这一知识点。
3.经过这段时间的javaFX学习我对javaFX的语法与c语言的EGE不同有了更多的了解,比如EGE的按钮和创建舞台和跳转页面等等与javaFX都不同,在今后的学习中我更应体会其中的不同之处,努力学习好JAVAFX。
4.遇到问题时,通过调试逐步找到问题所在,然后这几次作业中我仍然发现自己存在着许多的语法错误,在今后的学习中更应加强基础知识的学习,吃透书本中的内容及课堂中所学知识。
5.这几次作业给我最大的感触就是遇到问题就应该大胆地去猜测,有想法就用代码表示出来,多加调试验证自己的想法,多学习一些优秀程序员的代码,学习其中代码的优秀逻辑,编程能力才能进一步提升,而且编程就应该要以动手实践为主,不尝试就不知道可不可行。


浙公网安备 33010602011771号