Java-第1~3次作业总结
一、前言
题目集1
- 知识点:主要是Java的一些基本语法(输入输出,选择循环,字符串处理等)的应用
- 题量:一共8题,基本是语法的基本应用,题量不算大
- 难度:较低
- 最终得分:100
题目集2
- 知识点:类的基本应用,通过类封装程序来更好的维护程序
- 题量:一共8题,考察到类的运用以及Java的API中有关类的使用,题量一点点大
- 难度:还算简单
- 最终得分:100
题目集3
- 知识点:类的应用及设计,定义相关类,维护类与类之间的逻辑关系
- 题量:一共4题,其中三题是前面涉及到的稍稍改进即可,第二题需要自己判断程序并设计相关的类,维护之间的关系较为麻烦,总体题量还挺大
- 难度:难度一般,但是程序设计很繁琐
- 最终得分:100
二、设计与分析
题目集1
7-1~7-9
7-1. 分段函数处理,计算BMI并根据其数值对应输出
7-2. 单位换算,要注意浮点数的精度问题
7-3. 判断奇数,奇数加和
7-4. 分段处理契税、印花税、交易费、测绘费、权属登记费及取证费
7-5. 根据输入输出相应角色,注意非法情况处理
7-6. 处理学号,通过字符串剪切及String转Intger函数来获取学号信息,注意非法情况
7-7. 判断三角形的类型,依次根据是否为三角形、是否等边、是否等腰、是否直角进行判断,注意浮点数判等的方法
7-8. 按题意计算直至满足差值小于0.00001
7-9. 获取-1前的01字符串,注意非法情况
题目集2
7-1
封装一个学生类,包含属性学号、姓名、语文成绩、数学成绩、物理成绩
方法包括:计算总分、计算平均分
类图如下:
根据题目要求,设置以上类来处理学生的成绩
代码如下:
import java.util.Scanner;
class Student {
String num, name;
int Chinese, Mathematics, English;
int GetSum() { //总分
return Chinese + Mathematics + English;
}
double GetEve() { //平均分
double ave = 1.0 * (Chinese + Mathematics + English) / 3.0;
return ave;
}
}
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Student[] stu = new Student[5];
for (int i = 0; i < 5; i++) {
stu[i] = new Student();
stu[i].num = input.next();
stu[i].name = input.next();
stu[i].Chinese = input.nextInt();
stu[i].Mathematics = input.nextInt();
stu[i].English = input.nextInt();
System.out.println(stu[i].num + " " + stu[i].name + " " + stu[i].GetSum() + " " + String.format("%.2f",stu[i].GetEve()));
}
}
}
7-2
相较上题,成绩的int类型转变成类,成绩有几个部分组成,在设计中增加一个成绩类,成绩类的属性包括平时成绩、期末成绩
类图如下:
设计好以上类之后,开始处理程序要求,存储每个学生的三门课的成绩,并且要判断输入的合法性,再根据要求输出学生的总分以及三种平均分。
代码如下:
// package Homework;
import java.util.Objects;
import java.util.Scanner;
class Grade { //成绩类
int DailyPerformance;
int FinalGrade;
int GetGrade() {
return (int) Math.floor(0.4 * DailyPerformance + 0.6 * FinalGrade);
}
}
class Student { //学生类
String num, name;
Grade Chinese, Mathematics, English;
Student() {
Chinese = new Grade();
Mathematics = new Grade();
English = new Grade();
}
int GetSum() {
return Chinese.GetGrade() + Mathematics.GetGrade() + English.GetGrade();
}
double Daily() {
return 1.0 * (Chinese.DailyPerformance + Mathematics.DailyPerformance + English.DailyPerformance) / 3.0;
}
double Final() {
return 1.0 * (Chinese.FinalGrade + Mathematics.FinalGrade + English.FinalGrade) / 3.0;
}
double GetEve() {
return 1.0 * (Chinese.GetGrade() + Mathematics.GetGrade() + English.GetGrade()) / 3.0;
}
}
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Student[] stu = new Student[3];
for (int i = 0; i < 3; i++) {
stu[i] = new Student();
for (int j = 0; j < 3; j++) { //处理输入
stu[i].num = input.next();
stu[i].name = input.next();
String s = input.next();
if (Objects.equals(s, "语文")) {
stu[i].Chinese.DailyPerformance = input.nextInt();
stu[i].Chinese.FinalGrade = input.nextInt();
} else if (Objects.equals(s, "数学")) {
stu[i].Mathematics.DailyPerformance = input.nextInt();
stu[i].Mathematics.FinalGrade = input.nextInt();
} else {
stu[i].English.DailyPerformance = input.nextInt();
stu[i].English.FinalGrade = input.nextInt();
}
}
System.out.println(stu[i].num + " " + stu[i].name + " " + stu[i].GetSum() + " " + String.format("%.2f", stu[i].Daily()) + " " + String.format("%.2f", stu[i].Final()) + " " + String.format("%.2f", stu[i].GetEve()));
}
}
}
7-3~7-8
-
7-3
处理重复的数据,因为数据的范围可能会特别的大,我们不能直接开一个数据范围一样大的数组来标记;且输入量可能也会比较的大,不能每个数找一遍有无重复,所以我们需要在几乎O(nlogn)的范围来处理,易想到排序。故通过java封装的Arrays.sort函数对数据排序,再去判断有无重复数据。
-
7-4
去掉重复数据,依据7-3,我们可以通过java封装的Set类结合Vector来处理重复数据,并保留第一次出现的数据,按原始数据进行输出
-
7-5
题目已经给出主函数程序代码,以及需要构造的Student类的属性以及属性的特性,根据题目要求完善相应类的方法即可。
-
7-6
经纬度的换算转化,按要求进行转化即可
-
7-8
日期的相关处理,判断日期合法、判断闰年、获取日期在当年第几天、当月第几天、当周第几天、日期的时间差等,实际上在java的API中都有封装,但当时并不了解,所以都自己写的类属性及方法,写复杂了许多
7-7
题目帮我们设计好了菜单需要的相应的类
设计类如下:
-
菜品类
属性:菜品名称、单价
方法:计算菜品价格
-
菜谱类
属性:菜品数组
方法:查找菜品信息
-
点菜记录类
属性:菜品、份额
方法:计价
-
订单类
属性:订单上每一道的记录
方法:计算订单的总价、添加一条菜品信息
设计好以上类后,开始处理程序的要求
代码如下:
// import com.sun.org.apache.xpath.internal.operations.Or;
import java.util.Objects;
import java.util.Scanner;
import java.util.Vector;
class Dish {
String name;//菜品名称
int unit_price; //单价
Dish() {
}
Dish(String name, int unit_price) {
this.name = name;
this.unit_price = unit_price;
}
int getPrice(int portion) {//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份)
if (portion == 1) return unit_price;
if (portion == 2) return unit_price + (unit_price + 1) / 2;
return 2 * unit_price;
}
}
class Menu {
Dish[] dishs;//菜品数组,保存所有菜品信息
int n;
Menu(int n) {
this.n = n;
dishs = new Dish[n];
for (int i = 0; i < n; i++) dishs[i] = new Dish();
}
Dish SearthDish(String dishName) {//根据菜名在菜谱中查找菜品信息,返回Dish对象。
for (int i = 0; i < n; i++) {
if (Objects.equals(dishName, dishs[i].name)) return dishs[i];
}
return new Dish("-1", -1);
}
}
class Record {
String d;//菜品
int portion;//份额(1/2/3代表小/中/大份)
Record(String d, int portion) {
this.d = d;
this.portion = portion;
}
int getPrice(Menu menu) {//计价,计算本条记录的价格
Dish dish = menu.SearthDish(d);
if (Objects.equals(dish.name, "-1")) return -1;
return dish.getPrice(portion);
}
}
class Order {
Vector<Record> records = new Vector<>();//保存订单上每一道的记录
int getTotalPrice(Menu menu) {//计算订单的总价
int sum = 0;
for (int i = 0; i < records.size(); i++) {
int price = records.elementAt(i).getPrice(menu);
if (price == -1) System.out.println(records.elementAt(i).d + " does not exist");
else sum += price;
}
return sum;
}
void addARecord(String dishName, int portion) {//添加一条菜品信息到订单中。
Record dish = new Record(dishName, portion);
records.add(dish);
}
}
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Menu menu = new Menu(4);
menu.dishs[0] = new Dish("西红柿炒蛋", 15);
menu.dishs[1] = new Dish("清炒土豆丝", 12);
menu.dishs[2] = new Dish("麻婆豆腐", 12);
menu.dishs[3] = new Dish("油淋生菜", 9);
Order order = new Order();
while (true) {
String name;
int portion;
name = input.next();
if (Objects.equals(name, "end")) break;
else {
portion = input.nextInt();
order.addARecord(name, portion);
}
}
int sum = order.getTotalPrice(menu);
System.out.println(sum);
}
}
题目集三
7-1、7-3、7-4
均为前面题目集所涉及到的,日期的处理之前使用自构造类及方法实现,在此次题目集中更改为了使用javaAPI中相关类来完成。
7-2
需要处理课程成绩,特别复杂!
对这种比较麻烦,要处理很多事情的程序,先设计好有关的类,再完善逻辑处理,分配每个”功能“在哪里实现,主程序应该怎么去实现会使得更好处理些。
故我们先设计有关的类:
课程类(Course)、成绩类(Grade)、学生类(Student)、班级信息类(ClassInformation)、输入处理类(AddressInput)
类图如下
类的有关属性及方法设计如上
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<Course>();
Vector<ClassInformation> Class = new Vector<ClassInformation>();
Vector<Student> students = new Vector<Student>();
Vector<String> set = new Vector<String>();
String str;
while (true) {
str = input.nextLine();
if (Objects.equals(str, "end")) break;
boolean flag2 = true;
for (int i = 0; i < set.size(); i++)
if (Objects.equals(str, set.elementAt(i)))
flag2 = false;
if (!flag2)
continue;
AddressInput addressInput = new AddressInput(str);
Vector<String> temp = addressInput.Split();
int type = addressInput.GetTypeOfInput();
if (type == 1) { //合法课程
boolean 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(courses.elementAt(i).name, course.name))
flag = false;
if (!flag)
continue;
for (int i = 0; i < courses.size(); i++)
if (Objects.equals(course.name, courses.elementAt(i).name))
flag = false;
if (flag)
courses.add(course);
} else if (type == 2 || type == 3) {
boolean flag = true;
for (int i = 0; i < set.size(); i++) {
addressInput.str = set.elementAt(i);
Vector<String> temp2 = addressInput.Split();
if (Objects.equals(temp2.elementAt(0), temp.elementAt(0)) && Objects.equals(temp2.elementAt(1), temp.elementAt(1)) && Objects.equals(temp2.elementAt(2), temp.elementAt(2))) {
flag = false;
}
}
if (!flag) continue;
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 {
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 {
Grade grade = new Grade(courses.elementAt(idx_c), Integer.parseInt(temp.elementAt(3)));
// System.out.println(courses.elementAt(idx_c).AssessmentMethod + " " + grade.FinalGrade);
students.elementAt(idx).AddOneGrade(grade);
courses.elementAt(idx_c).AddOnGrade(grade);
set.add(str);
}
} else {
if (!Objects.equals(courses.elementAt(idx_c).AssessmentMethod, "考试")) {
System.out.println(temp.elementAt(0) + " " + temp.elementAt(1) + " " + ": access mode mismatch");
} else {
Grade grade = new Grade(courses.elementAt(idx_c), Integer.parseInt(temp.elementAt(3)), Integer.parseInt(temp.elementAt(4)));
// System.out.println(grade.DailyPerformance + " " + grade.FinalGrade);
students.elementAt(idx).AddOneGrade(grade);
courses.elementAt(idx_c).AddOnGrade(grade);
set.add(str);
}
}
}
} else if (type == -1) {
System.out.println("wrong format");
}
}
// 学生成绩信息处理
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).grades.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());
}
}
}
三、踩坑心得
- 对浮点数的精度处理问题,因为习惯了使用double类型处理小数问题,一些题目与float之间精度相差会有点大
- 对输入的处理不全面,处理不合法情况容易遗漏
- 在题目集2判重复数据时,在循环内定义了一个int数据类型,但没有及时释放,造成了内存泄漏,导致实际使用的内存空间为原来的两倍左右,导致最后内存超限
- 浮点数判相等不能使用
==
,因为计算机内部小数实际上很多都是近似表示,在通过系列计算后,即时计算过程等价,但结果不一定会完全相等,在一定的误差内可视作相等 - 要根据给定的数据范围及规模来设计算法,在题目集2的判重复元素中不能对每个数去找是否有重复,也不能通过数组标记因为数据的范围可能是很大的
四、改进意见
- 对浮点数问题,建议规定判断的方法,保留几位小数或者相对误差或绝对误差在一定的范围内视作正确,每次因为用的double而不是float而导致答案错误,真的很难调得出来,完全碰运气还浪费时间
- 对数据得范围以及输入量建议写全一些,题目集2的第三题,也没说n的范围,还有数据的范围,也不知道能不能O(n^2)通过,只能一种一种方法试,有点浪费时间
- 题目描述全面些,像题目集1有些要求对不和法输出相应语句,题目中都没有出现过,只能去网上借阅才知道要输出什么(这种真的调不了一点)
- 题目量有点点的大,特别是第三次
五、总结
- 从这三次的题目集,学到了java基本语法的使用以及代码的编写,完成类的属性构造及方法的实现,能独立为程序设计相关类并实现程序所需功能
- 在复杂的程序(题目集3的2题)中,要先设计好类,整理好逻辑关系,再去实现代码会较方便很多
- 三次的题目集考察的知识点有个递进的过程,在实现程序时,可以考虑java的API中有没有封装相应的类,可以减少很多的代码量(题目集2的日期处理就多了很多很多的代码行数)
- 进一步的了解java相较于c语言的优势,从面向过程逐渐向面向对象的思想转变,今后应该更进一步去了解java的继承、多态等。