前言
- 可以說,這一階段才是真正進入了面向對象程序設計的代碼設計與編寫,在此之前的幾次題目集只能算是讓我們熟悉從c語言語法到java語法使用的轉變,這體現在之前并未要求對類的使用。而這三次題目集,要求使用類并對其內部屬性進行封裝,
- 第一次題目集的難度較為簡單,題目量共5道,那個時候我以為"答題判題程序"只是簡單的作為一個題目集的最后一題,編寫需要提高難度,完全沒注意它其實是"答題判題程序-1"!!!,因為是第一次出現,這題的要求較未簡單,所以我也是簡單地使用了正則表達式以及類數組。
- 第二次題目集的配置是3道簡單題+更為困難的答題判題程序,最后一題在第一次題目集的基礎上增加了要求,并且各種信息也是亂序輸入的,雖然我因為本次第一題要求使用鏈表,學習了鏈表的簡單使用方法,但最后一題考慮到穩中求勝,還是使用了自己熟悉的類數組與正則表達式用法,并且在類數組里套數組【苦笑】。
- 第三次題目集2道簡單題+答題判題程序,最后一題我愿稱之為這三次題目集的KING,這次我使用的是HashMap,這是我之前未使用過的方法,在這次程序編寫過程中也是學到了HashMap的get方法、put方法等。這次最后一題難度可以說是直線上升,難度除了有28個測試點之外,還有多種判題信息的輸出。有幾個測試點不明確錯誤點,一直不知道怎么修改好。
設計與分析
- 第一次題目集
1. 以下是我此次程序的UML圖

2. 以下是我對此次程序設計的類圖

3.main函數
public class Main
{
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int i = 0;
int j = 0;
int n = Integer.parseInt(in.nextLine());
test[] t = new test[100];
String[] q = new String[100];
String[] a = new String[100];
String line;
String message = "";
String regex3 = "(?<=#A:).*";
String end = "end";
for(j = 0;j<n;j++)
{
line = in.nextLine();
Pattern pat = Pattern.compile("#N:\\s*(\\d+)\\s+#Q:\\s*(.*?)\\s+#A:\\s*(.*)");
Matcher mat = pat.matcher(line);
if(mat.find())
{
i = Integer.parseInt(mat.group(1));
q[i] = new String(mat.group(2));
a[i] = new String(mat.group(3));
}
}
line = in.next();
for(i = 1;i<=n&&!(line.equals(end));i++)
{
Pattern pat3 = Pattern.compile(regex3);
Matcher mat3 = pat3.matcher(line);
if(mat3.find())
{
message = new String(mat3.group());
}
t[i] = new test(q[i],a[i],message);
line = in.next();
}
for(i = 1;i<=n;i++)
{
System.out.println(t[i].getQuestion()+"~"+t[i].getMessage());
}
for(i = 1;i<=n;i++)
{
if(i == 1)
System.out.printf("%s",t[i].compare());
else
System.out.printf(" %s",t[i].compare());
}
}
}
4. test類設計
class test
{
private String answer;
private String question;
private String message;
public test(){
}
public test(String question,String anwser,String message)
{
this.question = question;
this.answer = anwser;
this.message = message;
}
public String getQuestion()
{
return question;
}
public String getAnswer()
{
return answer;
}
public String getMessage()
{
return message;
}
public void setMessage(String message)
{
this.message = message;
}
public boolean compare()
{
boolean ret = (answer.equals(message));
return ret;
}
}
第一次題目集最后一題寫得十分簡潔,其一是因為題目較為簡單(至少不是第三次的難度),其二是因為初步著手寫面向對象程序語言,對此類程序的編寫規則并不明晰,例如不知道使用類的必要、單一職責原則等。但能夠對類內數據進行封裝操作。
- 第二次題目集
1. 以下是我此次程序的UML圖

2. 以下是我對此次程序設計的類圖

3. 源代碼
點擊查看代碼
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main
{
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int i = 0;
int j = 0;//試卷的編號
int k = 0;//答卷對應的試卷編號
int n = 0;//試卷內題目數量
int m = 0;//答卷的數組編號
int o = 0;
int num = 0;
Question[] q = new Question[1000];
Paper[] p = new Paper[1000];
Answer[] a = new Answer[1000];
String line;
String question;
String answer;
String end = "end";
Pattern pat = Pattern.compile("#N:\\s*(\\d+)\\s+#Q:\\s*(.*?)\\s+#A:\\s*(.*)");
Pattern pat1 = Pattern.compile("#T:(\\d+)");
Pattern pat2 = Pattern.compile("#S:(\\d+)");
Pattern pat3 = Pattern.compile("(\\d+)-(\\d+)");
Pattern pat4 = Pattern.compile("#A:(\\S+)");
line = in.nextLine();
while(!line.equals(end))
{
Matcher mat = pat.matcher(line);
Matcher mat1 = pat1.matcher(line);
Matcher mat2 = pat2.matcher(line);
Matcher mat3 = pat3.matcher(line);
Matcher mat4 = pat4.matcher(line);
if(mat.find())
{
i = Integer.parseInt(mat.group(1));
question = new String(mat.group(2));
answer = new String(mat.group(3));
q[i] = new Question(question,answer);
}
else if(line.startsWith("#T:"))
{
if(mat1.find())
j = Integer.parseInt(mat1.group(1));
p[j] = new Paper();
// 匹配題目編號和分值
while (mat3.find()) {
p[j].add(mat3.group(1),mat3.group(2),n);
n++;
}
if(p[j].Sum(n))
{
System.out.println("alert: full score of test paper"+j+" is not 100 points");
}
}
else if(line.startsWith("#S:"))
{
if(mat2.find())
k = Integer.parseInt(mat2.group(1));
a[m] = new Answer(k);
while (mat4.find()) {
a[m].add(mat4.group(1),o);
o++;
}
m++;
}
line = in.nextLine();
}
for(i = 0;i<m;i++)
{
int[] sum = new int[100];
num = a[i].getNum();//編號
if(p[num]!=null)
{
for(j = 0;j<n;j++)
{
if(a[i].getAnswer(j)!=null)
{
int r = Integer.parseInt(p[num].getNum(j));
System.out.println(q[r].getQuestion()+"~"+a[i].getAnswer(j)+"~"+a[i].compare(q[r].getAnswer(), j));
if(a[i].compare(q[r].getAnswer(), j))
{
sum[j] = p[num].getScore(j);
}
}
else
{
sum[j] = 0;
System.out.println("answer is null");
}
}
for(k = 0;k<=j;k++)
{
if(k == 0)
{
sum[j] += sum[k];
System.out.printf("%d", sum[k]);
}
else if(k == j)
System.out.printf("~%d\n", sum[k]);
else
{
sum[j] += sum[k];
System.out.printf(" %d", sum[k]);
}
}
}
else
{
System.out.println("The test paper number does not exist");
}
}
}
}
class Question
{
private String answer;
private String question;
public Question(){
}
public Question(String question,String anwser)
{
this.question = question;
this.answer = anwser;
}
public String getQuestion()
{
return question;
}
public String getAnswer()
{
return answer;
}
public boolean compare(String message)
{
boolean ret = (answer.equals(message));
return ret;
}
}
class Paper
{
private String[] num = new String[1000];//題號
private int[] score = new int[1000];//分值
private int n;
public Paper() {
}
public void add(String num,String score,int i)
{
this.num[i] = num;
int s = Integer.parseInt(score);
this.score[i] = s;
}
public boolean Sum(int n)
{
this.n = n;
int sum = 0;
int j;
boolean ret = true;
for(j = 0;j<n;j++)
{
sum+=score[j];
}
if(sum == 100)
ret = false;
return ret;
}
public String getNum(int j)
{
return num[j];
}
public int getScore(int j)
{
return score[j];
}
}
class Answer
{
private String[] answer = new String[1000];
private int num = 0;
private int i = 0;
public Answer() {
}
public Answer(int num)
{
this.num = num;
}
public void add(String answer,int i)
{
this.answer[i] = answer;
}
public int getNum()
{
return num;
}
public String getAnswer(int i)
{
return answer[i];
}
public boolean compare(String a,int n)
{
return a.equals(answer[n]);
}
}
相比于第一次題目集,我在第二次題目集拆分了多個類,其難點在于亂序輸入以及不定數量的字符串;
- 第三次題目集
1. 以下是我此次程序的UML圖


2. 以下是我對此次程序設計的類圖

3. 以下是我的main函數,可以看出,我對main函數的編寫過于冗長,在這一點上沒有很好地遵循單一職責原則,我認為這一部分的改進體現在類中方法的增多以及類的增多。例如增加正則表達式類、類中匹配方法等等。
點擊查看代碼
public class Main
{
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
boolean Qisexit,Sisexit,Pisexit;
int Qcount = 0;//題目數量
int Pcount = 0;//試卷數量
int Pnum = 0;//試卷號
int Tcount = 0;//單張試卷中題目數量
int Acount = 0;//答卷數量
int Anum = 0;//答卷號
int Dcount = 0;//單張答卷中答案數量
int Qnum = 0,Snum = 0,Tnum = 0;
int[] score = new int[1000];
int i = 0,j = 0,k = 0,n = 0,num = 0,sum = 0,sid = 0;
HashMap<Integer,Question> q = new HashMap<Integer,Question>();
HashMap<Integer,Answer> a = new HashMap<Integer,Answer>();
HashMap<Integer,Paper> p = new HashMap<Integer,Paper>();
HashMap<Integer,Student> s = new HashMap<Integer,Student>();
String line;
String end = "end";
Pattern pat = Pattern.compile("#N:\\s*(\\d+) +#Q:\\s*(.*?) +#A:\\s*(.*)");
Pattern pat1 = Pattern.compile("#T:(\\d+)");
Pattern pat2 = Pattern.compile("#S:(\\d+) (\\d+)");
Pattern pat3 = Pattern.compile("(\\d+)-(\\d+)");
Pattern pat4 = Pattern.compile("(\\d+) (\\S[A-Za-z]+)");
Pattern pat5 = Pattern.compile("#D:N-(\\d+)");
Pattern pat6 = Pattern.compile("#A:(\\d+)-");
line = in.nextLine();
while(!line.equals(end))
{
Matcher mat = pat.matcher(line);
Matcher mat1 = pat1.matcher(line);
Matcher mat2 = pat2.matcher(line);
Matcher mat3 = pat3.matcher(line);
Matcher mat4 = pat4.matcher(line);
Matcher mat5 = pat5.matcher(line);
Matcher mat6 = pat6.matcher(line);
if(mat.find())//題目信息
{
Qcount = Integer.parseInt(mat.group(1));
Question Qclass = new Question(mat.group(2),mat.group(3));
q.put(Qcount, Qclass);
}
else if(line.startsWith("#T:"))//試卷信息
{
Pcount++;
if(mat1.find())
Pnum = Integer.parseInt(mat1.group(1));
Paper Pclass = new Paper(Pnum);
// 匹配題目編號和分值
while (mat3.find()) {
Qisexit = true;
Tcount++;
Tnum = Integer.parseInt(mat3.group(1));
if(q.get(Tnum)==null)
Qisexit = false;
Pclass.add(Tnum,Integer.parseInt(mat3.group(2)),Qisexit,Tcount);
}
p.put(Pcount, Pclass);
}
else if(line.startsWith("#S:"))//答卷信息
{
Sisexit = true;
Pisexit = true;
Acount++;
if(mat2.find())
{
Anum = Integer.parseInt(mat2.group(1));
sid = Integer.parseInt(mat2.group(2));
}
if(p.get(Anum)==null)
Pisexit = false;
if(s.get(sid)==null)
{
Sisexit = false;
}
Answer Aclass = new Answer(Anum,mat2.group(2),Pisexit,Sisexit);
while(mat6.find())
{
Dcount++;
Aclass.add(Integer.parseInt(mat6.group(1)),"");
}
while (mat3.find())
{
Dcount++;
Aclass.add(Integer.parseInt(mat3.group(1)),mat3.group(2));
}
a.put(Acount, Aclass);
}
else if(line.startsWith("#X:"))//學生信息
{
while(mat4.find())
{
Snum = Integer.parseInt(mat4.group(1));
Student Sclass = new Student(mat4.group(2));
s.put(Snum, Sclass);
}
}
else if(mat5.find())
{
q.get(2).Delete();
}
else
System.out.println("wrong format:"+line);
line = in.nextLine();
}
for(i = 1;i<=Pcount;i++)//試卷滿分相關信息的輸出
{
if(p.get(i).Sum())
System.out.println("alert: full score of test paper"+i+" is not 100 points");
}
for(i = 1;i<=Acount;i++)//答題信息輸出
{
Answer an = a.get(i);
num = an.getAnum();
if(!an.getPisexit())
System.out.println("The test paper number does not exist");
else
{
Paper pa = p.get(num);
for(j = 1,n = -1;j<=pa.getTcount();j++)
{
n++;
if(!an.getScanf(j))
{
System.out.println("answer is null");
}
else
{
Qnum = pa.getNum(j);
if(!pa.getExit(j))
{
System.out.println("non-existent question~0");
}
else
{
if(q.get(Qnum).getIsdelete())
{
System.out.println("the question "+Qnum+" invalid~0");
}
else
{
System.out.println(q.get(Qnum).getQuestion()+"~"+an.getAnswer(j)+"~"+an.compare(q.get(Qnum).getAnswer(), j));
if(an.compare(q.get(Qnum).getAnswer(), j))
{
score[n] = pa.getScore(Qnum);
sum += score[n];
}
}
}
}
}
sid = Integer.parseInt(an.getSid());
if(!an.getSisexit())
System.out.println(sid+" not found");
else
{
System.out.printf(sid+" "+s.get(sid).getName()+":");
for(k = 0;k<=n;k++)
{
System.out.printf(" %d",score[k]);
}
System.out.println("~"+sum);
}
}
}
}
}
4. 以下是我四個類的編寫
各種類內的編寫,方法各職責單一
題目類
class Question//題目信息類
{
private String answer;
private String question;
private boolean isdelete;
public Question(){
}
public Question(String question,String anwser)
{
this.question = question;
this.answer = anwser;
isdelete = false;
}
public String getQuestion()
{
return question;
}
public String getAnswer()
{
return answer;
}
public boolean getIsdelete()
{
return isdelete;
}
public boolean compare(String message)
{
boolean ret = (answer.equals(message));
return ret;
}
public void Delete()
{
isdelete = true;
}
}
試卷類
class Paper//試卷信息類
{
private HashMap<Integer,Integer> num = new HashMap<Integer,Integer>();//題號
private HashMap<Integer,Integer> score = new HashMap<Integer,Integer>();//分值
private HashMap<Integer,Boolean> exit = new HashMap<Integer,Boolean>();//題號存在
private int Pnum;
private int Tcount = 0;
public Paper(int Pnum) {
this.Pnum = Pnum;
}
public void add(int num,int score,Boolean isexit,int i)
{
this.num.put(i, num);
this.score.put(i, score);
this.exit.put(i, isexit);
Tcount ++;
}
public boolean Sum()
{
int sum = 0;
int j;
boolean ret = true;
for(j = 1;j<=Tcount;j++)
{
sum+=score.get(j);
}
if(sum == 100)
ret = false;
return ret;
}
public int getPnum() {
return Pnum;
}
public int getTcount() {
return Tcount;
}
public int getNum(int j)
{
return num.get(j);
}
public int getScore(int j){
return score.get(j);
}
public boolean getExit(int j) {
return exit.get(j);
}
}
答卷類
class Answer//答卷信息類
{
private HashMap<Integer,Boolean> scanf = new HashMap<Integer,Boolean>();//題號順序
private HashMap<Integer,String> answer = new HashMap<Integer,String>();//答案
private boolean Pisexit;
private boolean Sisexit;
private String sid;
private int Anum;
private int Dcount = 0;
public Answer(int Asum,String sid,boolean Pisexit,boolean Sisexit)
{
this.Anum = Asum;
this.sid = sid;
this.Pisexit = Pisexit;
this.Sisexit = Sisexit;
}
public void add(int num,String answer)
{
this.scanf.put(num, true);
this.answer.put(num, answer);
Dcount++;
}
public int getDcount() {
return Dcount;
}
public int getAnum() {
return Anum;
}
public boolean getPisexit() {
return Pisexit;
}
public boolean getSisexit() {
return Sisexit;
}
public boolean getScanf(int i)
{
boolean ret = true;
if(scanf.get(i)==null)
ret = false;
return ret;
}
public String getAnswer(int i)
{
return answer.get(i);
}
public String getSid()
{
return sid;
}
public boolean compare(String a,int n)
{
return a.equals(answer.get(n));
}
}
學生類
class Student
{
private String name;
public Student(String name)
{
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
踩坑心得
- 第三次題目集
1. 在增加下圖第十個測試樣例后,我也相應改進了我的代碼。

在此之前
我的存儲代碼是這樣的
else if(line.startsWith("#T:"))//試卷信息{
Pcount++;
if(mat1.find())
Pnum = Integer.parseInt(mat1.group(1));
Paper Pclass = new Paper(Pnum);
// 匹配題目編號和分值
while (mat3.find()) {
Tcount++;
Pclass.add(Integer.parseInt(mat3.group(1)),Integer.parseInt(mat3.group(2)),Tcount);
}
p.put(Pcount, Pclass);
}
else if(line.startsWith("#S:"))//答卷信息
{
Acount++;
if(mat2.find())
Asum = Integer.parseInt(mat2.group(1));
Answer Aclass = new Answer(Asum,mat2.group(2));
while (mat3.find())
{
Dcount++;
Aclass.add(mat3.group(1),mat3.group(2),Dcount);
}
a.put(Acount, Aclass);
}
根據其中的
但本題不考慮引用的題目在被引用的信息之后出現的情況
這句話
我增加了輸入答卷信息是題目是否存在的判斷以及答卷輸入時學生是否已存在
else if(line.startsWith("#T:"))//屬于試卷信息{
Pcount++;
if(mat1.find())
Pnum = Integer.parseInt(mat1.group(1));
Paper Pclass = new Paper(Pnum);
// 匹配題目編號和分值
while (mat3.find()) {
Qisexit = true;
Tcount++;
Tnum = Integer.parseInt(mat3.group(1));
if(q.get(Tnum)==null)//查找題目是否在此條信息輸入時存在
Qisexit = false;
Pclass.add(Tnum,Integer.parseInt(mat3.group(2)),Qisexit,Tcount);
}
p.put(Pcount, Pclass);
}
else if(line.startsWith("#S:"))//答卷信息{
Sisexit = true;
Pisexit = true;
Acount++;
if(mat2.find()){
Anum = Integer.parseInt(mat2.group(1));
sid = Integer.parseInt(mat2.group(2));
}
if(p.get(Anum)==null)//查找題目是否在此條信息輸入時存在
Pisexit = false;
if(s.get(sid)==null)//查找學生是否在此條信息輸入時存在
Sisexit = false;
Answer Aclass = new Answer(Anum,mat2.group(2),Pisexit,Sisexit);
while(mat6.find()){
Dcount++;
Aclass.add(Integer.parseInt(mat6.group(1)),"");
}
while (mat3.find()){
Dcount++;
Aclass.add(Integer.parseInt(mat3.group(1)),mat3.group(2));
}
a.put(Acount, Aclass);
}
改進建議
測試點的說明可以盡量詳細些,有個別測試點不明白為什么錯,所以修改時卡了很久。
總結
1. 收獲
在編寫這幾次代碼的過程中,我有以下收獲
- 鏈表的簡單使用
- HashMap的使用
- HashMap的內部存儲空間表示
- 正則表達式的寫法。
- 類的封裝
- 類與類間的使用
2. 發現
java作為面向對象程序,需要考慮到類的分工使用,以及單一職責原則,因此代碼量也大大提升,但代碼具有了良好的低耦合度,在修改時也非常便利。
3. 改進
我的main函數總是過于冗長,這是下次題目集需要改進的一點,將部分可以增加進類的方法不在main函數內實現,實現低耦合度這一特點,否則,太多操作堆積在main函數內,不僅使代碼的可閱讀性降低,還會導致后期修改時十分繁瑣。
浙公網安備 33010602011771號