Java-第7~8次作业总结
一、前言
-
知识点:
-
HashMap
HashMap是Map接口的一个实现类(HashMap实现了Map的接口),它具有Map的特点。HashMap的底层是哈希表结构。 Map是用于保存具有映射关系的数据集合,它具有双列存储的特点,即一次必须添加两个元素,即一组键值对==><Key,Value>,其中Key的值不可重复(当Key的值重复的时候,后面插入的对象会将之前插入的具有相同的Key值的对象覆盖掉),Value的值可重复。 底层原理:(红黑树实现) HashMap内部利用数组存储数据;根据Key的 hashCode 值计算出数组的下标位置,进行添加或者查询数据。根据 hashCode 计算出数组的下标位置的算法称为“散列算法”;数组的下标位置会重复,重复的时候利用链表存储重复元素,这个链表称为“散列桶”;添加和查询的时候如果有”散列桶“,则根据 equals 方法逐个比较找到位置。 常用操作: 1、添加元素: HashMap.put(key,value) 2、访问元素 value=HashMap.get(key) 3、删除元素 HashMap.remove(key) 4、计算大小 HashMap.size(); 5、遍历 for(DateType value:HashMap){} 其它常用方法: clear() 删除 hashMap 中的所有键/值对 isEmpty() 判断 hashMap 是否为空 containsKey() 检查 hashMap 中是否存在指定的 key 对应的映射关系 containsValue() 检查 hashMap 中是否存在指定的 value 对应的映射关系 replace() 替换 hashMap 中是指定的 key 对应的 value replaceAll() 将 hashMap 中的所有映射关系替换成给定的函数所执行的结果 forEach() 对 hashMap 中的每个映射执行指定的操作 entrySet() 返回 hashMap 中所有映射项的集合集合视图 keySet() 返回 hashMap 中所有 key 组成的集合视图 values() 返回 hashMap 中存在的所有 value 值 merge() 添加键值对到 hashMap 中 compute() 对 hashMap 中指定 key 的值进行重新计算 自定义排序:(例子) Map<String, Tuple> linkedHashMap1 = new LinkedHashMap<>(); map.entrySet().stream().sorted(Map.Entry.comparingByKey(new Comparator<String>() { public int compare(String o1, String o2) { return o2.compareTo(o1); } })).forEach(o -> linkedHashMap1.put(o.getKey(), o.getValue())); for (Map.Entry<String, Tuple> entry : linkedHashMap1.entrySet()) { System.out.println(entry.getKey() + " " + entry.getValue().name + " " + entry.getValue().grade); }
-
ArrayList-排序
方法一:
实现Comparator接口
Collections.sort(arrayList, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { Comparator<Object> compare = Collator.getInstance(Locale.CHINA); if (o1.math + o1.physics < o2.math + o2.physics) return 1; else if (o1.math + o1.physics == o2.math + o2.physics) return 0; return -1; } });
方法二:
使用lambda表达式
arrayList.sort((a, b) -> { String aa = a.num.substring(6, 14); String bb = b.num.substring(6, 14); if (aa.compareTo(bb) > 0) return 1; else if (aa.compareTo(bb) < 0) return -1; return 0; });
-
自定义接口
基本过程:
自定义接口类,可以理解为声明方法类
interface IntegerStack { public Integer push(Integer item); public Integer pop(); public Integer peek(); public boolean empty(); public int size(); }
自定义实现类,实现接口类中声明的方法的算法
class ArrayIntegerStack implements IntegerStack { int size = 0; int r; public Integer[] arr; ArrayIntegerStack(int size) { this.size = size; r = 0; arr = new Integer[size]; } public String toString() { return Arrays.toString(arr); } public Integer push(Integer item) { if (item == null || r == size) return null; arr[r++] = item; return item; } public Integer pop() { if (r == 0) return null; return arr[--r]; } //出栈,如果为空,则返回null。出栈时只移动栈顶指针,相应位置不置为null public Integer peek() { if (r == 0) return null; return arr[r - 1]; } //获得栈顶元素,如果为空,则返回null. public boolean empty() { return r == 0; } //如果为空返回true public int size() { return r; } //返回栈中元素个数 }
接口中的方法不能用静态,因为接口是抽象类,而静态是一定实现
-
覆盖与重写
覆盖(Overriding)是指在子类中重新定义父类中已经存在的方法,并且方法签名(方法名、参数列表和返回类型)完全相同。覆盖允许子类提供自己的实现方法,以替代父类中的相同命名方法。当通过父类引用调用该方法时,将会执行子类中的覆盖方法。覆盖涉及到继承关系和多态性,并且需要通过使用@Override注解来明确标记。
重写(Overloading)是指在同一个类中,通过改变方法的参数列表来定义多个方法,这些方法具有相同的名称但具有不同的参数。重写不改变方法的返回类型和名称,但根据不同的参数类型和/或参数数量,提供了方法的多个版本。重载用于在同一个类中提供更灵活的方法调用方式,并根据不同的参数自动调用相应的方法。
区别:
1.覆盖是在继承关系中,子类重新定义父类中的方法,方法签名完全相同;而重载是在同一个类中,通过改变方法的参数列表来定义多个方法,方法名相同但参数列表不同。 2.覆盖是多态性的一种表现,通过父类引用调用方法时,会根据实际对象类型执行相应的覆盖方法;而重载是在编译时根据参数列表类型和数量确定调用哪个方法。 3.覆盖需要使用@Override注解来明确标记;而重载不需要任何特殊的标记。
-
-
题量:这次的迭代增加的需求要比菜单程序少,也会更简单一些,需要重构的代码量小,题量还是算少的
-
难度:感觉算是很正常的难度,比之前的又加桌号又加预订、电话、客户啥的好得多
-
结果:两次题目集都是100
二、设计与分析
题目集7
7-4 课程成绩统计程序-2
题目描述
相对课程成绩统计程序1增加了实验课:
- 实验课成绩规则定义为:课程每次实验成绩的平均分,实验课的成绩必须为实验
- 输入实验课程信息格式:学号+
- 输出实验课成绩格式:课程名称+
程序应输出信息:
- 输出不合法情况下应输出信息
- 学生课程总成绩平均分按学号由低到高排序输出
- 单门课程成绩平均分分为三个分值:平时成绩平均分(可选)、期末考试平均分、总成绩平均分,按课程名称的字符顺序输出
- 班级所有课程总成绩平均分按班级由低到高排序输出
类结构设计
- AddressInput类:用来处理输入,返回输入信息的类别
- Score类:各种成绩的父类,包含属性课程名;包含方法获取成绩
- FinalScore类:Score的一个子类,是考察方式的分数对象
- HaveDailyPerformanceScore类:Score的一个子类,是考试方式的分数对象
- ExperimentalScore类:Score的一个子类,是实验方式的分数对象
- Course类:存储某门课程的成绩记录
- Student类:存储某个学生的个人信息以及成绩信息
- ClassInformation类:存储某个班级的班级信息以及成绩信息
主程序设计
通过输入处理类获得输入类型
- 输入课程信息:得到此条信息的课程类,查找该课程是否已存在,若不存在则加入到courses中,否则不进行任何处理
- 输入成绩记录:获取输入的总评方式,针对每种考核方式分别进行处理,得到相应的Score成绩记录子类
- 考查方式成绩记录:在Score的scores属性中加入一条成绩信息
- 考试方式成绩记录:在Score的scores属性中加入两条成绩信息
- 实验方式成绩记录:在Score的scores属性中加入
cnt
条成绩信息 - 不合法格式:输出
wrong format
最后输出学生总成绩、课程平均成绩、班级平均成绩
类图如下
SourceMonitor生成报表
代码如下
//可点击“折叠”折叠代码
import java.text.Collator;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Vector<Course> courses = new Vector<>();
Vector<ClassInformation> Class = new Vector<>();
Vector<Student> students = new Vector<>();
String str;
while (true) {
str = input.nextLine();
if (Objects.equals(str, "end")) break;
AddressInput addressInput = new AddressInput(str);
Vector<String> temp = addressInput.Split();
int type = addressInput.GetTypeOfInput();
boolean flag;
switch (type) {
case 1: //课程信息
flag = true;
Course course = new Course(temp.elementAt(0), temp.elementAt(1), temp.elementAt(2));
for (int i = 0; i < courses.size(); i++)
if (Objects.equals(course.name, courses.elementAt(i).name))
flag = false;
if (flag)
courses.add(course);
break;
case 2: //考察/考试 成绩信息
case 3:
case 4:
int idx = -1, idx_c = -1;
for (int i = 0; i < students.size(); i++) //学生下标
if (Objects.equals(temp.elementAt(0), students.elementAt(i).num))
idx = i;
if (idx == -1) {
Student stu = new Student(temp.elementAt(0), temp.elementAt(1));
students.add(stu);
idx = students.size() - 1;
}
for (int i = 0; i < courses.size(); i++) //课程下标
if (Objects.equals(temp.elementAt(2), courses.elementAt(i).name))
idx_c = i;
if (idx_c == -1) {
System.out.println(temp.elementAt(2) + " " + "does not exist");
} else {
boolean ok;
if (temp.size() == 4) { //考察
if (!Objects.equals(courses.elementAt(idx_c).AssessmentMethod, "考察")) {
System.out.println(temp.elementAt(0) + " " + temp.elementAt(1) + " " + ": access mode mismatch");
} else {
Score score = getScore(temp);
ok = students.elementAt(idx).AddOneGrade(score);
if (ok)
courses.elementAt(idx_c).AddOnGrade(score);
}
} else if (temp.size() == 5) { //考试
if (!Objects.equals(courses.elementAt(idx_c).AssessmentMethod, "考试")) {
// if (Objects.equals(courses.elementAt(idx_c).AssessmentMethod, "实验"))
// System.out.println("wrong format");
// else
System.out.println(temp.elementAt(0) + " " + temp.elementAt(1) + " " + ": access mode mismatch");
} else {
Score score = getScore(temp);
ok = students.elementAt(idx).AddOneGrade(score);
if (ok)
courses.elementAt(idx_c).AddOnGrade(score);
}
} else {
if (!Objects.equals(courses.elementAt(idx_c).AssessmentMethod, "实验") || temp.size() - 4 != Integer.parseInt(temp.elementAt(3))) {
System.out.println(temp.elementAt(0) + " " + temp.elementAt(1) + " " + ": access mode mismatch");
} else {
Score score = getScore(temp);
ok = students.elementAt(idx).AddOneGrade(score);
if (ok)
courses.elementAt(idx_c).AddOnGrade(score);
}
}
}
break;
case -1: //输入格式问题
System.out.println("wrong format");
break;
default:
break;
}
}
// 学生成绩信息处理
students.sort((a, b) -> {
if (a.num.compareTo(b.num) > 0) return 1;
else if (a.num.compareTo(b.num) < 0) return -1;
return 0;
});
for (int i = 0; i < students.size(); i++) { //学生课程平均分
int idx = -1;
for (int j = 0; j < Class.size(); j++)
if (Objects.equals(Class.elementAt(j).ClassNum, students.elementAt(i).num.substring(0, 6)))
idx = j;
if (idx == -1) {
ClassInformation cla = new ClassInformation(students.elementAt(i).num.substring(0, 6));
Class.add(cla);
idx = Class.size() - 1;
}
if (students.elementAt(i).scores.isEmpty())
System.out.println(students.elementAt(i).num + " " + students.elementAt(i).name + " " + "did not take any exams");
else {
System.out.println(students.elementAt(i).num + " " + students.elementAt(i).name + " " + students.elementAt(i).GetGrade());
Class.elementAt(idx).ClassMembers.add(students.elementAt(i));
}
}
//课程信息处理
Collections.sort(courses, new Comparator<Course>() {
@Override
public int compare(Course o1, Course o2) {
Comparator<Object> compare = Collator.getInstance(java.util.Locale.CHINA);
return compare.compare(o1.name, o2.name);
}
});
for (int i = 0; i < courses.size(); i++) { //学生课程平均分
courses.elementAt(i).Print();
}
//班级信息
for (int i = 0; i < Class.size(); i++) {
if (Class.elementAt(i).ClassMembers.isEmpty())
System.out.println(Class.elementAt(i).ClassNum + " " + "has no grades yet");
else
System.out.println(Class.elementAt(i).ClassNum + " " + Class.elementAt(i).GetAverage());
}
}
private static Score getScore(Vector<String> s) {
if (s.size() == 4) { //考察
FinalScore score = new FinalScore();
score.name = s.elementAt(2);
score.TextScore = Integer.parseInt(s.elementAt(3));
return score;
} else if (s.size() == 5) { //考试
HaveDailyPerformanceScore score = new HaveDailyPerformanceScore();
score.name = s.elementAt(2);
score.DailyPerformance = Integer.parseInt(s.elementAt(3));
score.FinalGrade = Integer.parseInt(s.elementAt(4));
return score;
} else { //实验
ExperimentalScore score = new ExperimentalScore();
score.name = s.elementAt(2);
score.cnt = Integer.parseInt(s.elementAt(3));
score.scores = new Vector<>();
for (int i = 4; i < s.size(); i++)
score.scores.add(Integer.parseInt(s.elementAt(i)));
return score;
}
}
}
class AddressInput {
String str;
AddressInput(String str) {
this.str = str;
}
public Vector<String> Split() {
Vector<String> temp = new Vector<>();
String[] s = str.split(" ");
Collections.addAll(temp, s);
return temp;
}
public int GetTypeOfInput() {
Vector<String> temp = this.Split();
if (temp.size() == 3) { //课程信息
Course course = new Course(temp.elementAt(0), temp.elementAt(1), temp.elementAt(2));
if (course.name.length() > 10 || !course.CourseType.matches("(选修|必修|实验)") || !course.AssessmentMethod.matches("(考试|考察|实验)")) {
return -1;
} else if (!course.JudgeLegitimacy()) {
System.out.println(course.name + " : course type & access mode mismatch");
return 0;
} else {
return 1;
}
} else if (temp.size() == 4) { //成绩 考察
String num = temp.elementAt(0);
String name = temp.elementAt(1);
String course = temp.elementAt(2);
String score1 = temp.elementAt(3);
if (!num.matches("[0-9]{8}") || name.length() > 10 || course.length() > 10 || !score1.matches("0|[0-9]|[1-9][0-9]|100")) {
return -1;
}
return 2;
} else if (temp.size() == 5) { //成绩 考试
String num = temp.elementAt(0);
String name = temp.elementAt(1);
String course = temp.elementAt(2);
String score1 = temp.elementAt(3);
String score2 = temp.elementAt(4);
if (!num.matches("[0-9]{8}") || name.length() > 10 || course.length() > 10 || !score1.matches("0|[0-9]|[1-9][0-9]|100") || !score2.matches("0|[0-9]|[0-9][0-9]|100")) {
return -1;
}
return 3;
} else if (temp.size() > 5) {
String num = temp.elementAt(0);
String name = temp.elementAt(1);
String course = temp.elementAt(2);
int cnt = Integer.parseInt(temp.elementAt(3)); //成绩数量
if (!num.matches("[0-9]{8}") || name.length() > 10 || course.length() > 10 || !temp.elementAt(3).matches("[4-9]"))
return -1;
for (int i = 4; i < temp.size(); i++)
if (!temp.elementAt(i).matches("0|[0-9]|[1-9][0-9]|100")) return -1;
return 4;
} else {
return -1;
}
}
}
class Score {
// int FinalGrade; //最终成绩
public String name;
Score() {
}
public int getFinalGrade() {
return 0;
}
public int getDailyPerformance() {
return 0;
}
public int getFinal() {
return 0;
}
}
class FinalScore extends Score {
public int TextScore;
FinalScore() {
}
FinalScore(int TextScore) {
this.TextScore = TextScore;
}
public int getFinalGrade() {
return TextScore;
}
}
class HaveDailyPerformanceScore extends Score {
public int DailyPerformance;
public int FinalGrade;
HaveDailyPerformanceScore() {
}
HaveDailyPerformanceScore(int DailyPerformance, int FinalGrade) {
this.DailyPerformance = DailyPerformance;
this.FinalGrade = FinalGrade;
}
public int getFinalGrade() {
return (int) Math.floor(0.3 * DailyPerformance + 0.7 * FinalGrade);
}
public int getDailyPerformance() {
return DailyPerformance;
}
public int getFinal() {
return FinalGrade;
}
}
class ExperimentalScore extends Score {
int cnt; //次数
Vector<Integer> scores;
ExperimentalScore() {
}
ExperimentalScore(int cnt, Vector<Integer> scores) {
this.cnt = cnt;
this.scores = scores;
}
public int getFinalGrade() {
int sum = 0;
for (int i = 0; i < scores.size(); i++) sum += scores.elementAt(i);
return (int) Math.floor(1.0 * sum / cnt);
}
}
class Course {
public String name;
public String CourseType; //必修/选修/实验
public String AssessmentMethod; //考试、考察、实验
public Vector<Score> scores;
Course() {
scores = new Vector<>();
}
Course(String name, String CourseType, String AssessmentMethod) {
this.name = name;
this.CourseType = CourseType;
this.AssessmentMethod = AssessmentMethod;
scores = new Vector<>();
}
public boolean JudgeLegitimacy() { //判断课程与考核方式的合法性
if (Objects.equals(CourseType, "必修"))
return Objects.equals(AssessmentMethod, "考试");
else if (Objects.equals(CourseType, "实验"))
return Objects.equals(AssessmentMethod, "实验");
else if (Objects.equals(CourseType, "选修"))
return !Objects.equals(AssessmentMethod, "实验");
return false;
}
public void AddOnGrade(Score score) {
scores.add(score);
}
public int GetDailyPerformanceAve() {
int sz = scores.size();
int sum = 0;
for (int i = 0; i < sz; i++) {
sum += scores.elementAt(i).getDailyPerformance();
}
return (int) Math.floor(1.0 * sum / sz);
}
public int GetFinalGradeAve() {
int sz = scores.size();
int sum = 0;
for (int i = 0; i < sz; i++) {
sum += scores.elementAt(i).getFinal();
}
return (int) Math.floor(1.0 * sum / sz);
}
public int GetGradeAve() {
int sum = 0;
int sz = scores.size();
for (int i = 0; i < sz; i++) {
sum += scores.elementAt(i).getFinalGrade();
}
return (int) Math.floor(1.0 * sum / sz);
}
public Vector<Integer> GetAllAve() {
Vector<Integer> ans = new Vector<Integer>();
if (Objects.equals(AssessmentMethod, "考试")) {
ans.add(GetDailyPerformanceAve());
ans.add(GetFinalGradeAve());
ans.add(GetGradeAve());
} else if (Objects.equals(AssessmentMethod, "考察")) {
ans.add(GetGradeAve());
ans.add(GetGradeAve());
} else {
ans.add(GetGradeAve());
}
return ans;
}
public void Print() {
if (scores.isEmpty())
System.out.println(name + " " + "has no grades yet");
else {
System.out.print(name);
Vector<Integer> ans = GetAllAve();
for (int i = 0; i < ans.size(); i++) {
System.out.print(" " + ans.elementAt(i));
}
System.out.println();
}
}
}
class Student {
public String num;
public String name;
public Vector<Score> scores;
Student() {
scores = new Vector<Score>();
}
Student(String num, String name) {
this.name = name;
this.num = num;
scores = new Vector<>();
}
public boolean AddOneGrade(Score score) {
boolean flag = true;
for (int i = 0; i < scores.size(); i++)
if (Objects.equals(score.name, scores.elementAt(i).name))
return false;
scores.add(score);
return true;
}
public int GetGrade() { //学生平均成绩
int size = scores.size();
int sum = 0;
for (int i = 0; i < size; i++) {
sum += scores.elementAt(i).getFinalGrade();
}
return (int) Math.floor(1.0 * sum / size);
}
}
class ClassInformation {
public String ClassNum;
public Vector<Student> ClassMembers;
ClassInformation(String ClassNum) {
this.ClassNum = ClassNum;
ClassMembers = new Vector<Student>();
}
public int GetAverage() {
int sum = 0;
int size = ClassMembers.size();
int cnt = 0;
for (int i = 0; i < size; i++) {
for (int j = 0; j < ClassMembers.elementAt(i).scores.size(); j++) {
sum += ClassMembers.elementAt(i).scores.elementAt(j).getFinalGrade();
cnt++;
}
}
return (int) Math.floor(1.0 * sum / cnt);
}
}
题目集8
7-1 课程成绩统计程序-3
题目描述
相对课程成绩统计程序2修改了计算总成绩的方法,并将其继承关系改为组合关系
成绩信息由课程成绩类和分项成绩类组成,课程成绩类组合分项成绩类,分项成绩类由成绩分值和权重两个属性构成。
对比继承关系和组合关系,在实现课程成绩统计2中使用的继承关系的子类之间并没有很强的相关性,没有完全体现出继承较强的可扩展性和复用性;而换成组合关系会更适应考核方式的变化,将课程成绩分成成绩类和分项成绩类会更合理些。
程序应输出信息:
- 输出不合法情况下应输出信息
- 学生课程总成绩平均分按学号由低到高排序输出
- 单门课程成绩平均分分为三个分值:平时成绩平均分(可选)、期末考试平均分、总成绩平均分,按课程名称的字符顺序输出
- 班级所有课程总成绩平均分按班级由低到高排序输出
类结构设计
- AddressInput类:用来处理输入,返回输入信息的类别
- Score类:存储单项的分数和权重
- Course类:存储某门课程的成绩记录
- Student类:存储某个学生的个人信息以及成绩信息
- ClassInformation类:存储某个班级的班级信息以及成绩信息
主程序设计
通过输入处理类获得输入类型
- 输入课程信息:得到此条信息的课程类,查找该课程是否已存在,若不存在则加入到courses中并将该课程各项考核的权重存入,否则不进行任何处理
- 输入成绩记录:获取输入的总评方式,针对每种考核方式分别进行处理,得到相应的Score成绩记录子类
- 考查方式成绩记录:在Score的scores属性中加入一条成绩信息
- 考试方式成绩记录:在Score的scores属性中加入两条成绩信息
- 实验方式成绩记录:在Score的scores属性中加入
cnt
条成绩信息 - 不合法格式:输出
wrong format
最后输出学生总成绩、课程平均成绩、班级平均成绩
类图如下
SourceMonitor生成报表
代码如下:
//可点击“折叠”折叠代码
import java.text.Collator;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Vector<Course> courses = new Vector<>();
Vector<ClassInformation> Class = new Vector<>();
Vector<Student> students = new Vector<>();
String str;
while (true) {
str = input.nextLine();
if (Objects.equals(str, "end")) break;
AddressInput addressInput = new AddressInput(str);
Vector<String> temp = addressInput.Split();
int type = addressInput.GetTypeOfInput();
boolean flag;
switch (type) {
case 1: //课程信息
if (temp.size() > 5) {
if (temp.size() - 4 != Integer.parseInt(temp.elementAt(3))) {
System.out.println(temp.elementAt(0) + " : number of scores does not match");
continue;
}
}
flag = true;
Course course = new Course(temp.elementAt(0), temp.elementAt(1), temp.elementAt(2));
for (int i = 0; i < courses.size(); i++)
if (Objects.equals(course.name, courses.elementAt(i).name))
flag = false;
if (Objects.equals(course.AssessmentMethod, "考试")) {
if (temp.size() == 5) {
course.weight.add(Double.parseDouble(temp.elementAt(3)));
course.weight.add(Double.parseDouble(temp.elementAt(4)));
} else {
course.weight.add(0.3);
course.weight.add(0.4);
}
} else if (Objects.equals(course.AssessmentMethod, "考察")) {
course.weight.add(1.0);
} else {
int cnt = Integer.parseInt(temp.elementAt(3));
if (cnt != temp.size() - 4) {
System.out.println();
continue;
}
double sum = 0;
for (int i = 4; i < temp.size(); i++) {
course.weight.add(Double.parseDouble(temp.elementAt(i)));
sum += Double.parseDouble(temp.elementAt(i));
}
if (Math.abs(sum - 1.0) > 0.0001) {
System.out.println(course.name + " : weight value error");
continue;
}
}
if (flag)
courses.add(course);
break;
case 2: //考察/考试 成绩信息
case 3:
case 4:
int idx = -1, idx_c = -1;
for (int i = 0; i < students.size(); i++) //学生下标
if (Objects.equals(temp.elementAt(0), students.elementAt(i).num))
idx = i;
if (idx == -1) {
Student stu = new Student(temp.elementAt(0), temp.elementAt(1));
students.add(stu);
idx = students.size() - 1;
}
for (int i = 0; i < courses.size(); i++) //课程下标
if (Objects.equals(temp.elementAt(2), courses.elementAt(i).name))
idx_c = i;
if (idx_c == -1) {
System.out.println(temp.elementAt(2) + " " + "does not exist");
} else {
boolean ok;
if (temp.size() == 4) { //考察
if (!Objects.equals(courses.elementAt(idx_c).AssessmentMethod, "考察")) {
System.out.println(temp.elementAt(0) + " " + temp.elementAt(1) + " " + ": access mode mismatch");
} else {
Score score = getScore(temp);
score.weight = FindWeight(score.name, courses);
ok = students.elementAt(idx).AddOneGrade(score);
if (ok)
courses.elementAt(idx_c).AddOnGrade(score);
}
} else if (temp.size() == 5) { //考试
if (!Objects.equals(courses.elementAt(idx_c).AssessmentMethod, "考试")) {
// if (Objects.equals(courses.elementAt(idx_c).AssessmentMethod, "实验"))
// System.out.println("wrong format");
// else
System.out.println(temp.elementAt(0) + " " + temp.elementAt(1) + " " + ": access mode mismatch");
} else {
Score score = getScore(temp);
score.weight = FindWeight(score.name, courses);
ok = students.elementAt(idx).AddOneGrade(score);
if (ok)
courses.elementAt(idx_c).AddOnGrade(score);
}
} else {
if (!Objects.equals(courses.elementAt(idx_c).AssessmentMethod, "实验")) {
System.out.println(temp.elementAt(0) + " " + temp.elementAt(1) + " " + ": access mode mismatch");
} else {
Score score = getScore(temp);
score.weight = FindWeight(score.name, courses);
if (score.weight.size() != score.score.size()) {
System.out.println(temp.elementAt(0) + " " + temp.elementAt(1) + " " + ": access mode mismatch");
} else {
ok = students.elementAt(idx).AddOneGrade(score);
if (ok)
courses.elementAt(idx_c).AddOnGrade(score);
}
}
}
}
break;
case -1: //输入格式问题
System.out.println("wrong format");
break;
default:
break;
}
}
// 学生成绩信息处理
students.sort((a, b) -> {
if (a.num.compareTo(b.num) > 0) return 1;
else if (a.num.compareTo(b.num) < 0) return -1;
return 0;
});
for (int i = 0; i < students.size(); i++) { //学生课程平均分
int idx = -1;
for (int j = 0; j < Class.size(); j++)
if (Objects.equals(Class.elementAt(j).ClassNum, students.elementAt(i).num.substring(0, 6)))
idx = j;
if (idx == -1) {
ClassInformation cla = new ClassInformation(students.elementAt(i).num.substring(0, 6));
Class.add(cla);
idx = Class.size() - 1;
}
if (students.elementAt(i).scores.isEmpty())
System.out.println(students.elementAt(i).num + " " + students.elementAt(i).name + " " + "did not take any exams");
else {
System.out.println(students.elementAt(i).num + " " + students.elementAt(i).name + " " + students.elementAt(i).GetGrade());
Class.elementAt(idx).ClassMembers.add(students.elementAt(i));
}
}
//课程信息处理
Collections.sort(courses, new Comparator<Course>() {
@Override
public int compare(Course o1, Course o2) {
Comparator<Object> compare = Collator.getInstance(java.util.Locale.CHINA);
return compare.compare(o1.name, o2.name);
}
});
for (int i = 0; i < courses.size(); i++) { //学生课程平均分
courses.elementAt(i).Print();
}
//班级信息
for (int i = 0; i < Class.size(); i++) {
if (Class.elementAt(i).ClassMembers.isEmpty())
System.out.println(Class.elementAt(i).ClassNum + " " + "has no grades yet");
else
System.out.println(Class.elementAt(i).ClassNum + " " + Class.elementAt(i).GetAverage());
}
}
private static Vector<Double> FindWeight(String name, Vector<Course> courses) {
Vector<Double> weight = new Vector<>();
for (int i = 0; i < courses.size(); i++)
if (Objects.equals(courses.elementAt(i).name, name))
weight = courses.elementAt(i).weight;
return weight;
}
private static Score getScore(Vector<String> s) {
Score score = new Score();
if (s.size() == 4) { //考察
score.name = s.elementAt(2);
score.num = 1;
score.score.add(Integer.parseInt(s.elementAt(3)));
} else if (s.size() == 5) { //考试
score.name = s.elementAt(2);
score.score.add(Integer.parseInt(s.elementAt(3)));
score.score.add(Integer.parseInt(s.elementAt(4)));
} else { //实验
score.name = s.elementAt(2);
for (int i = 3; i < s.size(); i++)
score.score.add(Integer.parseInt(s.elementAt(i)));
return score;
}
return score;
}
}
class AddressInput {
String str;
AddressInput(String str) {
this.str = str;
}
public Vector<String> Split() {
Vector<String> temp = new Vector<>();
String[] s = str.split(" ");
Collections.addAll(temp, s);
return temp;
}
public int GetTypeOfInput() {
Vector<String> temp = this.Split();
if (temp.size() == 3 || !(str.charAt(0) >= '0' && str.charAt(0) <= '9')) { //课程信息
Course course = new Course(temp.elementAt(0), temp.elementAt(1), temp.elementAt(2));
if (temp.size() > 5) {
for (int i = 4; i < temp.size(); i++) {
if (!temp.elementAt(i).matches("0.[0-9]+")) {
return -1;
}
}
if (!temp.elementAt(3).matches("0|[0-9]|[1-9][0-9]|100") || !temp.elementAt(3).matches("[4-9]")) {
return -1;
}
} else {
for (int i = 3; i < temp.size(); i++) {
if (!temp.elementAt(i).matches("0.[0-9]+")) {
return -1;
}
}
}
if (course.name.length() > 10 || !course.CourseType.matches("(选修|必修|实验)") || !course.AssessmentMethod.matches("(考试|考察|实验)")) {
return -1;
} else if (!course.JudgeLegitimacy()) {
System.out.println(course.name + " : course type & access mode mismatch");
return 0;
} else {
return 1;
}
} else if (temp.size() == 4) { //成绩 考察
String num = temp.elementAt(0);
String name = temp.elementAt(1);
String course = temp.elementAt(2);
String score1 = temp.elementAt(3);
if (!num.matches("[0-9]{8}") || name.length() > 10 || course.length() > 10 || !score1.matches("0|[0-9]|[1-9][0-9]|100")) {
return -1;
}
return 2;
} else if (temp.size() == 5) { //成绩 考试
String num = temp.elementAt(0);
String name = temp.elementAt(1);
String course = temp.elementAt(2);
String score1 = temp.elementAt(3);
String score2 = temp.elementAt(4);
if (!num.matches("[0-9]{8}") || name.length() > 10 || course.length() > 10 || !score1.matches("0|[0-9]|[1-9][0-9]|100") || !score2.matches("0|[0-9]|[0-9][0-9]|100")) {
return -1;
}
return 3;
} else if (temp.size() > 5) {
String num = temp.elementAt(0);
String name = temp.elementAt(1);
String course = temp.elementAt(2);
if (!num.matches("[0-9]{8}") || name.length() > 10 || course.length() > 10)
return -1;
for (int i = 3; i < temp.size(); i++)
if (!temp.elementAt(i).matches("0|[0-9]|[1-9][0-9]|100")) return -1;
return 4;
} else {
return -1;
}
}
}
class Score {
public String name;
public int num;
public Vector<Integer> score;
public Vector<Double> weight;
Score() {
score = new Vector<>();
weight = new Vector<>();
}
public int getFinalGrade() {
double ans = 0;
for (int i = 0; i < weight.size(); i++) {
ans += weight.elementAt(i) * score.elementAt(i);
}
return (int) Math.floor(ans + 0.0001);
}
public int getDailyPerformance() {
return score.elementAt(0);
}
public int getFinal() {
return score.elementAt(1);
}
}
class Course {
public String name;
public String CourseType; //必修/选修/实验
public String AssessmentMethod; //考试、考察、实验
public Vector<Score> scores;
public Vector<Double> weight;
Course() {
scores = new Vector<>();
weight = new Vector<>();
}
Course(String name, String CourseType, String AssessmentMethod) {
this.name = name;
this.CourseType = CourseType;
this.AssessmentMethod = AssessmentMethod;
scores = new Vector<>();
weight = new Vector<>();
}
public boolean JudgeLegitimacy() { //判断课程与考核方式的合法性
if (Objects.equals(CourseType, "必修"))
return Objects.equals(AssessmentMethod, "考试");
else if (Objects.equals(CourseType, "实验"))
return Objects.equals(AssessmentMethod, "实验");
else if (Objects.equals(CourseType, "选修"))
return !Objects.equals(AssessmentMethod, "实验");
return false;
}
public void AddOnGrade(Score score) {
scores.add(score);
}
public int GetDailyPerformanceAve() {
int sz = scores.size();
int sum = 0;
for (int i = 0; i < sz; i++) {
sum += scores.elementAt(i).getDailyPerformance();
}
return (int) Math.floor(1.0 * sum / sz);
}
public int GetFinalGradeAve() {
int sz = scores.size();
int sum = 0;
for (int i = 0; i < sz; i++) {
sum += scores.elementAt(i).getFinal();
}
return (int) Math.floor(1.0 * sum / sz);
}
public int GetGradeAve() {
int sum = 0;
int sz = scores.size();
for (int i = 0; i < sz; i++) {
sum += scores.elementAt(i).getFinalGrade();
}
return (int) Math.floor(1.0 * sum / sz);
}
public Vector<Integer> GetAllAve() {
Vector<Integer> ans = new Vector<Integer>();
if (Objects.equals(AssessmentMethod, "考试")) {
// ans.add(GetDailyPerformanceAve());
// ans.add(GetFinalGradeAve());
ans.add(GetGradeAve());
} else if (Objects.equals(AssessmentMethod, "考察")) {
// ans.add(GetGradeAve());
ans.add(GetGradeAve());
} else {
ans.add(GetGradeAve());
}
return ans;
}
public void Print() {
if (scores.isEmpty())
System.out.println(name + " " + "has no grades yet");
else {
System.out.print(name);
Vector<Integer> ans = GetAllAve();
for (int i = 0; i < ans.size(); i++) {
System.out.print(" " + ans.elementAt(i));
}
System.out.println();
}
}
}
class Student {
public String num;
public String name;
public Vector<Score> scores;
Student() {
scores = new Vector<Score>();
}
Student(String num, String name) {
this.name = name;
this.num = num;
scores = new Vector<>();
}
public boolean AddOneGrade(Score score) {
boolean flag = true;
for (int i = 0; i < scores.size(); i++)
if (Objects.equals(score.name, scores.elementAt(i).name))
return false;
scores.add(score);
return true;
}
public int GetGrade() { //学生平均成绩
int size = scores.size();
int sum = 0;
for (int i = 0; i < size; i++) {
sum += scores.elementAt(i).getFinalGrade();
}
return (int) Math.floor(1.0 * sum / size);
}
}
class ClassInformation {
public String ClassNum;
public Vector<Student> ClassMembers;
ClassInformation(String ClassNum) {
this.ClassNum = ClassNum;
ClassMembers = new Vector<Student>();
}
public int GetAverage() {
int sum = 0;
int size = ClassMembers.size();
int cnt = 0;
for (int i = 0; i < size; i++) {
for (int j = 0; j < ClassMembers.elementAt(i).scores.size(); j++) {
sum += ClassMembers.elementAt(i).scores.elementAt(j).getFinalGrade();
cnt++;
}
}
return (int) Math.floor(1.0 * sum / cnt);
}
}
期末考试
客观题
- 关于覆盖和重载:覆盖只有发生在父类与子类之间,而重载可以发生在同一个类中
- 如果一个类的成员被protected修饰,那么这个成员既能被同一包下的其它类访问,也能被不同包下该类的子类访问
- 构造函数是类的一种特殊函数,它的方法名必须与类名相同,一般在创建新对象时,系统会自动调用构造函数
- .java文件编译后,每一个class对应一个.class文件;Java源代码编译后产生的.class是字节码文件;.class文件在JVM上运行
编程题
1. 立体图形问题
考察知识点继承和多态的应用,正方体和正三棱锥继承父类Solid,维护程序的可扩展性
//可点击“折叠”折叠代码
import java.util.*;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
double side = input.nextDouble();
display(new Cube(side));
display(new RegularPyramid(side));
}
static void display(Solid o) {
System.out.printf("%.2f%n",o.getAres());
System.out.printf("%.2f%n",o.getV());
}
}
class Solid {
public double side;
public Solid(double side) {
this.side = side;
}
Solid() {
}
public double getAres() {
return side * side * 6;
}
public double getV() {
return side * side * side;
}
}
class Cube extends Solid {
public Cube(double side) {
this.side = side;
}
public double getAres() {
return side * side * 6;
}
public double getV() {
return side * side * side;
}
}
class RegularPyramid extends Solid {
public RegularPyramid(double side) {
this.side = side;
}
public double getAres() {
return side * side * Math.sqrt(3);
}
public double getV() {
return side * side * side * Math.sqrt(2) / 12;
}
}
2. 魔方问题
考察继承和多态,正方体魔方和正三棱锥魔方继承魔方父类,重新定义了边长的计算方法:
魔方边长=阶数*单元边长
//可点击“折叠”折叠代码
import java.util.*;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
String color = input.next();
int layer = input.nextInt();
double side = input.nextDouble();
RubikCube cube1 = new SquareCube(color, layer, new Cube(side));
color = input.next();
layer = input.nextInt();
side = input.nextDouble();
RubikCube cube2 = new RegularPyramidCube(color, layer, new RegularPyramid(side));
display(cube1);
display(cube2);
}
static void display(RubikCube o) {
System.out.println(o.color);
System.out.printf("%.2f%n", o.getAres());
System.out.printf("%.2f%n", o.getV());
}
}
class Solid {
public double side;
public Solid(double side) {
this.side = side;
}
Solid() {
}
public double getAres() {
return side * side * 6;
}
public double getV() {
return side * side * side;
}
}
class Cube extends Solid {
public Cube(double side) {
this.side = side;
}
public double getAres() {
return side * side * 6;
}
public double getV() {
return side * side * side;
}
}
class RegularPyramid extends Solid {
public RegularPyramid(double side) {
this.side = side;
}
public double getAres() {
return side * side * Math.sqrt(3);
}
public double getV() {
return side * side * side * Math.sqrt(2) / 12;
}
}
class RubikCube {
public String color;
public int layer;
public Solid solid;
RubikCube(String color, int layer, Solid solid) {
this.color = color;
this.solid = solid;
this.layer = layer;
}
public RubikCube() {
}
public double getAres() {
return solid.getAres() * layer * layer;
}
public double getV() {
return solid.getV() * layer * layer * layer;
}
}
class SquareCube extends RubikCube {
SquareCube(String color, int layer, Solid solid) {
super();
this.color = color;
this.solid = solid;
this.layer = layer;
}
}
class RegularPyramidCube extends RubikCube {
RegularPyramidCube(String color, int layer, Solid solid) {
super();
this.color = color;
this.solid = solid;
this.layer = layer;
}
}
3. 魔方排序问题
考察接口的应用,定义Comparable实现自定义排序
Collections.sort(list, new Comparator<RubikCube>() {
@Override
public int compare(RubikCube o1, RubikCube o2) {
return (int) (o1.getV() - o2.getV());
}
});
4. 销售步枪问题
设计步枪机(lock)、枪托(stock)和枪管(barrel)三者之间存在关联关系
//可点击“折叠”折叠代码
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Lock lock = new Lock(45.0);
Stock stock = new Stock(30.0);
Barrel barrel = new Barrel(25.0);
int lockNum = input.nextInt();
int stockNum = input.nextInt();
int barrelNum = input.nextInt();
SalesOrder salesOrder = new SalesOrder(lockNum, stockNum, barrelNum);
if (lockNum > 70 || lockNum <= 0 || stockNum > 80 || stockNum <= 0 || barrelNum > 90 || barrelNum <= 0)
System.out.println("Wrong Format");
else {
double total = salesOrder.getTotal(lock, stock, barrel);
System.out.printf("%.2f ", total);
System.out.printf("%.2f%n", salesOrder.getCommission(total));
}
}
}
class SalesOrder {
public int lockNum = 0;
public int stockNum = 0;
public int barrelNum = 0;
SalesOrder() {
}
SalesOrder(int lockNum, int stockNum, int barrelNum) {
this.lockNum = lockNum;
this.barrelNum = barrelNum;
this.stockNum = stockNum;
}
public double getTotal(Lock lock, Stock stock, Barrel barrel) {
return lock.getPrice() * lockNum + stock.getPrice() * stockNum + barrel.getPrice() * barrelNum;
}
public double getCommission(double sales) {
double ans = 0;
if (sales >= 0) ans += Math.min(sales, 1000) * 0.1;
if (sales > 1000) ans += (Math.min(sales, 1800) - 1000) * 0.15;
if (sales > 1800) ans += (sales - 1800) * 0.2;
return ans;
}
}
class Barrel {
private double price = 0;
Barrel() {
}
Barrel(double price) {
this.price = price;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
class Stock {
private double price = 0;
Stock() {}
Stock(double price) {
this.price = price;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
class Lock {
private double price = 0;
Lock() {}
Lock(double price) {
this.price = price;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
三、踩坑心得
-
在期末考试中计算魔方的表面积和体积时会存在一个精度问题,因为魔方的边长与阶数是成正比的,且面积又与边长的平方成正比,体积与边长的立方成正比,将面积的计算在之前的基础上乘上相应个数个阶数,按理论上得到的结果是一样的,但因为计算机内部的计算问题,会产生一些精度误差,改成先计算出边长在计算表面积和体积才能过
-
因为一个笔误,将实验课的判断规则写错了,调了好几个世纪(
- 还是小数的精度问题,如果不是把测试样例开放出来了,估计怎么也找不到这个问题了。是小数计算上的问题,由于小数在计算机内部是使用二进制描述的,有些小数并不能被精确表示,而是舍去了部分的小数部分,就会导致相同的计算公式不同的计算顺序会出现不一样的结果,在题目集九中平均分的计算方式都是直接舍去小数部分,对
case 8
按照我的程序计算出来的结果刚好是86.99999999
被自动舍去了小数部分而变成了86导致了答案错误,但实际上是因为计算机内部的问题,所以我将小数部分舍去时加了一个较小的精度(0.00001
)可能可以稍微避免了这个问题
四、改进意见
- 在期末考试中计算魔方的表面积和体积时会存在一个精度问题,因为魔方的边长与阶数是成正比的,且面积又与边长的平方成正比,体积与边长的立方成正比,将面积的计算在之前的基础上乘上相应个数个阶数,按理论上得到的结果是一样的,但因为计算机内部的计算问题,会产生一些精度误差。但我觉得应该不是程序设计的问题,这两种方式按理都应该是对的,我觉得涉及到精度问题的程序的判定建议改成相对误差进行判定,有时候精度问题真的很难找得到,而且还是这种不同方法处理的情况
- 还是强烈建议之后有小数的问题都使用相对误差进行判定,而不是简单的保留几位小数让程序有个固定的结果,毕竟计算机内部计算小数本来就存在精度的问题结果本来就是不太准确的,通过绝对误差来判定结果难免会有些的不准确。
- 建议把一个系列的迭代时间别拉那么长,第一次的课程成绩的还是在国庆那时候,到现在再去写早就忘掉当时的程序了,还得先把之前的程序看一遍再写
五、总结
- 从这两次的题目集以及期末考试,学到了java基本语法的使用以及代码的编写,完成类的属性构造及方法的实现,能独立为程序设计相关类并实现程序所需功能
- 在复杂的程序中,要先设计好类,整理好逻辑关系,再去实现代码会较方便很多
- 其实当整个程序的类图设计好了之后,代码的编写是很简单的,在编写代码前先设计好程序的逻辑结构更为重要,能减轻不少的重构重写工作,逻辑也会更清晰
- 进一步的了解java相较于c语言的优势,从面向过程逐渐向面向对象的思想转变,今后应该更进一步去使用java的继承、多态以及接口等。
- 在实现程序功能的时候,也要尽量简化自己的程序结构,降低耦合度,增加健壮性。程序的开闭性还是很差,以至于圈复杂度都比较高,每次迭代需要修改的代码也多,之后的程序可以只当向这方面改进优化。
- 不能仅局限于pta的测试点,在编写程序时更需要考虑结构,尽量使得程序的可扩展性更好,符合开闭原则,能减少之后重构的大量工作