PTA总结
一.前言
- 题目集01有9道基础题,对if—else语句,switch语句,while语句等基础语法的使用,较为简单
- 题目集02有三道题,第一道题是不区分大小写的将a,b,c等字母转化为对应的数字1,2,3……难点在于如何避免代码过于繁琐,找到一种较为简单的转换方式,而不是switch或if-else去一一对应a与1,b与2第三题是从字符串中提取特定两个班级202017班、202061班同学的学号后四位输出,通过if语句固定8位学号的前6位,然后通过每8位的最后两位间的倍数关系输出8位学号的最后2位.本题集的难点在于根据字符串下标的准确检索符合题目要求的字符并打印,对知识的要求不高,但对思维方式有一些要求。
- 题目集03有4道题第一题是用类解一元二次方程,本题需要学生自己写题目涉及到的类,即对根的求解放在自己写的类中,主函数不参与根的运算,本题涉及到类的知识,但较为简单。接下来的三道题思路相似,都是计算当前天数的前n天,后n天,两个日期间有多少天。难点在于,年有闰年平年,天有28,29,30,31,因此就需要通过条件语句来判断平年闰年以及各月的天数。三四题是将第二题写为两种不同的聚合结构,下文将具体分析。涉及聚合的知识,本题目集较为困难。
二.设计与分析
- 题目集02-7-2
题目:起始位“0”,在有效数据之后加上1位可选的奇偶校验位和1位结束位“1”。请编写程序,模拟串口接收处理程序,注:假定有效数据是8位,奇偶校验位采用奇校验。
代码:import java.util.*;
public class Main {
public static void main(String[] args){
Scanner input=new Scanner(System.in);
String s=input.nextLine();
int flag=0,count=1,count1=0;
if(s.length()<11){
System.out.print("null data");
return;
}
for(int i=0;i
if (s.charAt(i) == '0') {
flag = 1;
break;
}
}
if(flag==0){
System.out.print("null data");
return;
}
int i=0;
while(i
if (s.charAt(i) == '0') {
if(s.charAt(i+10)=='1'){
for(int a=i+1;a
if(s.charAt(a)=='1'){
count1++;
}
}
if((s.charAt(i+9)=='1'&&count1%2==0)||(s.charAt(i+9)=='0'&&count1%2!=0)){
System.out.print(count+":");
for (int b=i+1;b
System.out.print(s.charAt(b));
}
System.out.println();
}else {
System.out.println(count+":"+"parity check error");
}
}else {
System.out.println(count+":"+"validate error");
}
i=i+10;
count++;
}
i++;
}
}
解释:我们从字符串的起始位置开始检查,当检查到0时,说明到了起始位,然后检查8位之后的奇校验位是否为0或1结束位是否为1若满足这些条件就从起始位的下一位开始打印到结束为为止,之后从结束位的下一位开始重复上述操作直到对字符串完成检查
心得:搞清楚什么是奇偶校验位,当校验位为1时,有效位要有偶数个1,当校验位为0时,有效位要有奇数个1.例如11101011,此时倒数第二位是1则前6位中就要有偶数个1,本例中就有4个。又例如01001101,此时倒数第二位是0则前6位中就要有奇数个1,本例中就有3个.搞清楚这个,该题就好些很多
- 题目集03-7-2
1. 题目:设计一个类DateUtil,求下n天,求前n天,求两个日期相差的天数
2. 类图:
3.代码:import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int year = 0;
int month = 0;
int day = 0;
int choice = input.nextInt();
if (choice == 1) { // test getNextNDays method
int m = 0;
year = Integer.parseInt(input.next());
month = Integer.parseInt(input.next());
day = Integer.parseInt(input.next());
DateUtil date = new DateUtil(year, month, day);
if (!date.checkInputValidity()) {
System.out.println("Wrong Format");
System.exit(0);
}
m = input.nextInt();
if (m < 0) {
System.out.println("Wrong Format");
System.exit(0);
}
System.out.print(date.getYear() + "-" + date.getMonth() + "-" + date.getDay() + " next " + m + " days is:");
System.out.println(date.getNextNDays(m).showDate());
} else if (choice == 2) { // test getPreviousNDays method
int n = 0;
year = Integer.parseInt(input.next());
month = Integer.parseInt(input.next());
day = Integer.parseInt(input.next());
DateUtil date = new DateUtil(year, month, day);
if (!date.checkInputValidity()) {
System.out.println("Wrong Format");
System.exit(0);
}
n = input.nextInt();
if (n < 0) {
System.out.println("Wrong Format");
System.exit(0);
}
System.out.print(
date.getYear() + "-" + date.getMonth() + "-" + date.getDay() + " previous " + n + " days is:");
System.out.println(date.getPreviousNDays(n).showDate());
} else if (choice == 3) { //test getDaysofDates method
year = Integer.parseInt(input.next());
month = Integer.parseInt(input.next());
day = Integer.parseInt(input.next());
int anotherYear = Integer.parseInt(input.next());
int anotherMonth = Integer.parseInt(input.next());
int anotherDay = Integer.parseInt(input.next());
DateUtil fromDate = new DateUtil(year, month, day);
DateUtil toDate = new DateUtil(anotherYear, anotherMonth, anotherDay);
if (fromDate.checkInputValidity() && toDate.checkInputValidity()) {
System.out.println("The days between " + fromDate.showDate() +
" and " + toDate.showDate() + " are:"
+ fromDate.getDaysofDates(toDate));
} else {
System.out.println("Wrong Format");
System.exit(0);
}
}
else{
System.out.println("Wrong Format");
System.exit(0);
}
}
class DateUtil{
private int year;
private int month;
private int day;
public DateUtil() {
}
public DateUtil(int year, int month, int day) {
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 checkInputValidity(){
int[] a={0,31,0,31,30,31,30,31,31,30,31,30,31};
if(isLeapYear(year)){
a[2]=29;
}else{
a[2]=28;
}
if(year>=1820&&year<=2020&&month>=1&&month<=12&&day<=a[month]&&day>0){
return true;
}else{
return false;
}
}//检测输入的年、月、日是否合法
public boolean isLeapYear(int year){
if((year % 4 == 0 && year % 100 != 0)||year % 400 == 0)
return true;
return false;
}//判断year是否为闰年
//int[] a={0,31,0,31,30,31,30,31,31,30,31,30,31};
public DateUtil getNextNDays(int n) {
int[] a = {31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
while(n>365) {
if (isLeapYear(year) && month <= 2) {
year = year + 1;
n = n - 366;
} else if (isLeapYear(year + 1) && month >= 3) {
year = year + 1;
n = n - 366;
}else{
year=year+1;
n=n-365;
}
}
if(isLeapYear(year)||isLeapYear(year+1)){
a[2]=29;
}
while(n>=a[month]){
n=n-a[month];
month=month+1;
if(month>12){
month=1;
}
}
day=day+n;
if(day>a[month]){
day=day-a[month];
month=month+1;
if(month>12){
month=1;
year=year+1;
}
}
return this;
}//取得year-month-day的下n天日期
public DateUtil getPreviousNDays(int n){
int[] a = {31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
while(n>365){
if(isLeapYear(year)&&month>2){
year=year-1;
n=n-366;
}else if(isLeapYear(year-1)&&month<=2){
year=year-1;
n=n-366;
}else {
year=year-1;
n=n-365;
}
}
if(isLeapYear(year)||isLeapYear(year-1)){
a[2]=29;
}
while(n>=a[month-1]){
n=n-a[month-1];
month=month-1;
if(month==0){
month=12;
year=year-1;
}
}
day=day-n;
if(day<0){
month=month-1;
day=a[month]+day;
if(month==0){
month=12;
year=year-1;
}
}
return this;
}//取得year-month-day的前n天日期
public int getDaysofDates(DateUtil date){
int[] a={0,31,28,31,30,31,30,31,31,30,31,30,31};
int sum=0;
if(isLeapYear(year)){
a[2]=29;
}
for(int i=month+1;i<=12;i++){
sum=sum+a[i];
}
sum=sum+a[month]-day;
for (int i=year+1;i
if ((isLeapYear(i))){
sum=sum+366;
}else {
sum=sum+365;
}
}
if(isLeapYear(date.getYear())){
a[2]=29;
}
for(int i=1;i
sum=sum+a[i];
}
sum=sum+date.day;
return sum;
}//求当前日期与date之间相差的天数
public String showDate(){
return (year+"-"+month+"-"+day);
}//以“year-month-day”格式返回日期值
解释:求下n天时,先判断当前年是不是闰年,以及当前月是不是小于等于2月,这是因为,当该年为闰年且当前月小于等于2月,那么要加到下一年的这一天就需要加366天,n就需要减366天,如果该年是平年下一年如果是闰年且当前月大于等于三月,那么从当前年加到下一年的同一天也要加366天,n-366天,例如2000 1 28到20001 1 28之间就是366,1999 3 28到2000 3 28之间是366天,如果当前年与下一年都是平年,则从当前年到下一年的同一天就需要加365,n-365,例如1998 1 1到1999 1 1之间就是加365天。N每减小一次年就加1,当n减到小于365时,此时判断当前年是否为闰年,如果是,就把2月份改为29天(初始化的二月份为28天),我们将月份存入对应的索引下标的数组中,例如a[1]=31,a[2]=28,a[3]=31……,当前月的当前天要到下个月的这一天需要加上当前月总天数,例如3 20号到4 20号需要31天,n每减少当前月的总天数,月就加一,当月大于12,月就变为1,年就加1例如1999 12 30,n减少12月份总天数31天后,日期变为2000 1 30.当n小于当前月的总天数,就把n加到当前天上,若当前天大于当前月的总天数时,当前天减去当前月的总天数得到新的天,月加1,并判断年是否需要加1.同样的道理,当求前n天时,需要判断当前年是闰年当前月是否大于2或下一年是闰年当前月是否小于等于2,n每次减少366天或365天其余部分和上述内容相同,思路也相似,不再重述。
当求两个日期之间差多少天时,我们不解释上述代码的思路,因为它存在缺陷,我们介绍另外一种思路,我们先算出起始年到输入的第一个日期之间一共有多少天,再算起始年到第二个日期之间有多少天例如本题起始年为1820 1 1假如输入的两个日期为1821 1 1和 1822 1 1,1821 1 1到起始年是366天,1822 1 1到起始年是731天,二者做差得365天,就是1821 1 1和 1822 1 1之间相差的天数。
题目集03-7-3
题目:与7-2相同
类图:
解释:类图看着比较混乱,但解释之后就很好理解,该题要求使用聚合的结构重写上一题,这个类图的意思就是,main只能认识dateutil类而dateutil只能调day类而day类只能调month类,month类只能调year类,举个例子,A只认识B,B只认识C,C只认识D,D只认识F,如果A想要一个只有F有的东西,A就只能先找B,B再找C,C再找D,D再找F,F给D,D给C……最后给到A,本题dateutil想要year,就要调day,day调month,month调year。
心得:显然这种结构是不合理的,更为合理的结构将在题目集03-7-4介绍
题目集03-7-4
题目:同上
类图:
解释:在该题中我们仍然将year,month,day分为三个类,不同于上一题的是,该题的聚合方式为dateutil可以同时调year,month,day,举例解释,A同时认识B,C,D当A想要D的东西时直接找D要,而不需要像上一题一样先找“中间商”。
三.踩坑心得
1.在题目集02-7-2中,我认识到在写代码前一定要理解题目的意思,最初我以为奇校验就是有效位中有奇数个1,显然这是不对的,即使写了代码也是错的,而在查出奇校验的真实含义后,很快就写出了代码。
2.不能投机取巧,在题目集03中,02,03,04三道题的测试点一样,如果只是将第二题的代码复制到3,4题,稍作修改也能过测试点,但是没有使用聚合,就丧失了实践聚合的机会
3.在计算前n天或后n天时,结果与正确值相差1天或两天,可能的错误是判断闰年平年时忘记修改2月份的日期,或者在循环过程中只记得将修改2月份为29天但是当年发生变化后忘记将2月份重新修改为28天
4.当计算总天数时要记得减一,就是说例如,1900 1 1到1901 1 5,先加年的365,再加天的5得370,而实际上1900 1 1加365是1901年1 月1日,到1月5日只有4天所以总天数是369.
四.改进建议
1.题目集03-7-1只计算了实数部分根的情况,没有考虑虚数。
2. 题目集03-7-3中耦合性过强,类与类之间要追求低耦合。
五.总结
1.我学到了什么
1.题目集01强化了基础知识,帮助我熟悉了基础语法的应用
2.题目集02增加了对String类的了解,例如string.charAt(),可以通过下表访问字符串对应位置的内容,string.subString()获取字符串的某一子函数.sting.split()可以以某些字符为节点分割字符串Datetype.praseDatetype()将字符串转化为数字
3.题目集03让我对聚合结构有了一定的感知,并能初步分辨不同聚合结构的优略
2.那些地方还需要进一步研究
1.对聚合结构还需要更深入的学习,可以参考课上讲的雨刷问题。
此为雨刷问题的初步类图,留于有缘人分析