学校希望根据同专业的同学们的绩点平均分班
,你需要打印出每个班级的所有学生信息
。
可以把这个问题分解成以下几个小任务:
创建一个名为
Student
的类,包含:
姓名(创建
Name
的类)
- 考虑
名
、中间名
、姓
- 学号:整型
加权平均绩点(创建
Grade
类并利用Arraylist
实现)
- 采用北京交通大学的五级九段制,详情请点击链接:
北京交通大学本科生课程考核与成绩管理办法创建一个名为
ClassInfo
的类,包含:
- 收集所有学生的个人信息,利用
Arraylist
实现- 对收集到的学生信息用
冒泡排序法
重新排序基于班级个数,用
"S"型排序
重新分班
什么是"S"型排序呢?
- 假设总共有三个班级,4位学生。我们将绩点由低到高的顺序,将第一位给1班,第二位给2班。如果班级人数不能整除学生人数也没关系,后面的排序方式依然由低到高,直到排完为止。如示意图所示:
![]()
- 通过绩点(调用
Arraylist
的方法)找到对应的学生信息- 打印各班学生信息
源码
Name
类代码如下:
/**
* @author Hephaest
* @version 6/04/2018
* @since jdk1.8.0_162
*/
public class Name
{
//声明实例变量
private String first;
private String second;
private String last;
private String fullName;
/**初始化构造方法,用 this 指向类中的实例变量,尤其是当调用的参数和内部声明参数一致时*/
//当没有中间名时
public Name(String first, String last)
{
this.first = first;
this.last = last;
}
//当有中间名时
public Name(String first, String second, String last)
{
this.first = first;
this.second = second;
this.last = last;
}
//判断是否有中间名,有的话注意是两个空格
public String getFullName()
{
if(second==null)
{
fullName=first+" "+last;
return fullName;
}
else
{
fullName=first+" "+second+" "+last;
return fullName;
}
}
}
Grade
类代码如下:
/**
* @author Hephaest
* @version 6/04/2018
* @since jdk1.8.0_162
*/
import java.util.*;
public class Grade {
private String rank;
private double grade;
private double xuefen;
/**
* 如果成绩是以等级形式给的,使用这个构造方法
* @param rank 等级
* @param xuefen 学分
*/
public Grade(String rank,double xuefen)
{
this.rank=rank;
this.xuefen=xuefen;
this.grade=0.0;
}
/**
* 如果成绩是以百分比或者直接就是绩点的形式,使用这个构造方法
* @param grade 百分比的成绩或绩点
* @param xuefen 学分
*/
public Grade(double grade,double xuefen)
{
this.grade=grade;
this.xuefen=xuefen;
this.rank="";
}
/* 考虑成绩是以哪种形式输入的,进入对应的判断语句
* 判断标准详见:http://www.bjtu.edu.cn/pub/xxgk/xxgksxqs/xsglfwxx/18999.htm
*/
public double getgrade()
{
if(rank.equalsIgnoreCase(""))
{
if(grade>100||grade<0)
{
System.out.println("Wrong input!");
grade=0.0;
xuefen=0.0;
return grade;
}
else if (grade>=96)
{
grade=5.0;
return grade;
}
else if (grade>=91)
{
grade=4.5;
return grade;
}
else if (grade>=86)
{
grade=4.0;
return grade;
}
else if (grade>=81)
{
grade=3.5;
return grade;
}
else if (grade>=76)
{
grade=3.0;
return grade;
}
else if (grade>=71)
{
grade=2.5;
return grade;
}
else if (grade>=66)
{
grade=2.0;
return grade;
}
else if (grade>=61)
{
grade=1.5;
return grade;
}
else if (grade>=60)
{
grade=1.0;
return grade;
}
else if(grade>=00&&grade<=5)
{
return grade;
}
else
{
grade=0.0;
return grade;
}
}
else
{ //因为输入的是一串字符串,所以要转换成一个个字符
char[] array= rank.toCharArray();
double grade=0.0;
for(int i=0;i<array.length;i++)
{
switch(array[i])
{
case 'A':
grade=4.0;
break;
case 'B':
grade=3.0;
break;
case 'C':
grade=2.0;
break;
case 'D':
grade=1.0;
break;
case 'F':
grade=0.0;
break;
case '+':
grade+=0.5;
break;
case '-':
if(grade<=0)
{
break;
}
else
{
grade-=0.5;
break;
}
default:
System.out.println("Your input is wrong!");
}
}
return grade;
}
}
public double getXuefen()
{
return xuefen;
}
}
Student
类代码如下:
/**
* @author Hephaest
* @version 6/04/2018
* @since jdk1.8.0_162
*/
import java.text.DecimalFormat;
import java.util.ArrayList;
public class Student
{
//用Name声明实例变量name,用ArrayList<grade> 声明grade
private Name name;
private int id;
private ArrayList<Grade> grade;
//如果没有中间名,使用这个构造方法进行实例化
public Student(String first, String last,
int id)
{
this.name = new Name(first, last);//调用之前写好的Name类
this.id = id;
grade=new ArrayList<Grade>();//调用已经在package有的Arraylist类
}
//如果有中间名,使用这个构造方法进行实例化
public Student(String first, String second, String last,
int id)
{
this.name = new Name(first, second, last);
this.id = id;
grade=new ArrayList<Grade>();
}
//直接获取Name里的方法,避免重写
public String getName()
{
return name.getFullName();
}
//一个学生可能有很多项成绩,链表的add方法就是在(单个)学生的成绩后面继续追加成绩,很实用的办法
public void addGrade(Grade newGrade)
{
grade.add(newGrade);
}
//把一个学生的所有成绩进行加权平均运算,得到最终的绩点
public double averageGPA()
{
double sum1=0.0;
double sum2=0.0;
for(int i = 0;i < grade.size(); i++)
{
sum1+=grade.get(i).getgrade()*grade.get(i).getXuefen();
sum2+=grade.get(i).getXuefen();
}
return sum1/sum2;
}
//获取学生学号
public int getID()
{
return id;
}
//对单个学生的所有信息进行打印,依次为:姓名-学号-平均绩点
public void print()
{
DecimalFormat fm = new DecimalFormat("#.##");
System.out.println("Name:\t " + getName()
+ "\nID:\t " + getID()
+ "\nGPA:\t" + fm.format(averageGPA()));
}
}
ClassInfo
类代码如下:
/**
* @author Hephaest
* @version 6/04/2018
* @since jdk1.8.0_162
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
public class ClassInfo {
private ArrayList<Student> students;
// 用 Arraylist 声明students
public ClassInfo()
{
students =new ArrayList<Student>();
}
/**
* initialInfo 用来获取控制台中输入的所有学生信息
* @param numberOfStudent 确定输入学生的个数
* @param newclas 输入创造的对象
*/
public void initialInfo(int numberOfStudent,Object newclas)
{
Scanner info=new Scanner (System.in);
ClassInfo newclass=(ClassInfo)newclas;
for(int i=0;i<numberOfStudent;i++)
{
System.out.println("Set the student's ID number:");
int number=info.nextInt();
System.out.println("Set the student's first name:");
String space = info.nextLine();
String first=info.nextLine();
System.out.println("Does student has second name?");
String answer=info.nextLine();
if(answer.equalsIgnoreCase("y"))
{
System.out.println("Set the student's second name:");
String second=info.nextLine();
System.out.println("Set the student's last name:");
String last=info.nextLine();
newclass.addStudent(new Student(first,second,last,number));
}
else
{
System.out.println("Set the student's last name:");
String last=info.nextLine();
newclass.addStudent(new Student(first,last,number));
}
System.out.println("Which types of grades you want to input:\n"+
"\t1:rank\n"+
"\t2:score\n");
int choice=info.nextInt();
switch(choice)
{
case 1:
System.out.println("Set the student's rank:");
space = info.nextLine();
String rank=info.nextLine();
System.out.println("Set the student's xuefen:");
double xuefen=info.nextDouble();
newclass.addNewRank(i,new Grade(rank,xuefen));
break;
case 2:
System.out.println("Set the student's score");
double score=info.nextDouble();
System.out.println("Set the student's xuefen");
double fen=info.nextDouble();
newclass.addNewScore(i,new Grade(score,fen));
break;
}
boolean flag=true;
while(flag==true)
{
System.out.println("Does any grade need to be added?");
space = info.nextLine();
answer=info.nextLine();
switch(answer)
{
case "Y":
case "y":
System.out.println("Which types of grades you"+
"want to input:\n"+
"\t1:rank\n"+
"\t2:score\n");
choice=info.nextInt();
space = info.nextLine();
switch(choice)
{
case 1:
System.out.println("Set the student's rank");
String rank=info.nextLine();
System.out.println("Set the student's xuefen");
double xuefen=info.nextDouble();
newclass.addNewRank(i,new Grade(rank,xuefen));
break;
case 2:
System.out.println("Set the student's score");
double score=info.nextDouble();
System.out.println("Set the student's xuefen");
double fen=info.nextDouble();
newclass.addNewScore(i,new Grade(score,fen));
break;
}
break;
case "n":
case "N":
flag=false;
break;
default:
System.out.println("Please answer \"yes\" or \"no\" !");
}
}
}
}
//students里追加学生(包括每个学生的所有信息)
public void addStudent(Student newStudent)
{
students.add(newStudent);
}
/**
* 这个方法实现每位学生可以拥有多个成绩,通过追加的方法
* @param index 代表学生链表中第几位学生
* @param newGrade grade对象(创建新的成绩)
*/
public void addNewScore(int index,Grade newGrade)
{
students.get(index).addGrade(newGrade);
}
/*
* 本质上与上面的方法一样,名字不同为了好区分新输入的成绩的形式
*/
public void addNewRank(int index,Grade newGrade)
{
students.get(index).addGrade(newGrade);
}
/*
* 这里使用泡沫排序法对学生的成绩进行排序
* 因为没有办法为Arraylist创建数组
* 因此用新的数组拷贝students里所有的成绩
* 注意:数组下表和students的下表并不是意义对应的关系
*/
public double[] bubbleSortStudent()
{
double temp;
int size = students.size();
double[] array=new double[size];
for (int i=0;i<size;i++)
{
array[i]=students.get(i).averageGPA();
}
for(int i = 0 ; i < size-1; i ++)
{
for(int j = 0 ;j < size-1-i ; j++)
{
if(array[j] > array[j+1])
{
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
return array;
}
/**
* 经过上面一步,我们成功把students里所有学生的成绩拷贝给数组array[i]
** 现在我们要做的就是根据学生的成绩分配到不同的班级
* 常用的方法是“S”型排法
* @param num 班级的总数
* @param array 泡沫排序完后的数组
* @return 分班完后的二维数组结果
*/
public double[][] allocateStudent(int num,double[] array)
{
int classNum=students.size()/num;
int classrest=students.size()%num;
classNum+=classrest;
double[][] arr=new double[num][classNum];
int k;
for(int j=0;j<num;j++)
{
k=j;
for(int i=0;i<classNum;i++)
{
if(k>=students.size())
{
break;
}
else
{
arr[j][i]=array[k];
k+=num;
}
}
}
return arr;
}
//找到需要删除的学生所在的students下标,调用remove方法即可
public void removeStudent(int studentEntry)
{
students.remove(studentEntry);
}
/**
* 打印每个班级的学生信息
* @param num 班级的总数
* @param arr 经过“S”型排列完的二维数组(可看作已经分班完的结果)
* 调用的是 allocateStudent 方法里返回的数组
* 注意:一般在公布分班情况的时候不会显示个体的成绩(确保隐私权)
* 这里体现是为了验证分班结果的正确性
*/
public void print(int num,double[][]arr)
{
for(int i=0;i<arr[0].length;i++)
{
System.out.println("Class"+(i+1)+" list:"+"\n");
System.out.println("--------------------");
for(int j=0;j<arr.length;j++)
{
for(int k=0;k<students.size();k++)
{
if(arr[i][j]==students.get(k).averageGPA())
{
students.get(k).print();
System.out.println("\n");
removeStudent(k);
}
}
}
}
}
//主方法
public static void main(String [] args)
{
ClassInfo newclass=new ClassInfo();
Scanner info=new Scanner (System.in);
System.out.println("Set the number of students:");
int numberOfStudent=info.nextInt();
newclass.initialInfo(numberOfStudent,newclass);
System.out.println("Set the number of classes:");
int number=info.nextInt();
newclass.print(number,newclass.allocateStudent(number,newclass.bubbleSortStudent()));
info.close();
}
}
输出结果:
Set the number of students:
3
Set the student's ID number:
20181201
Set the student's first name:
William
Does student has second name?
y
Set the student's second name:
Jefferson
Set the student's last name:
Smith
Which types of grades you want to input:
1:rank
2:score
1
Set the student's rank:
A+
Set the student's xuefen:
6
Does any grade need to be added?
Y
Which types of grades you want to input:
1:rank
2:score
2
Set the student's score
88
Set the student's xuefen
5
Does any grade need to be added?
N
Set the student's ID number:
20181145
Set the student's first name:
James
Does student has second name?
n
Set the student's last name:
Bush
Which types of grades you want to input:
1:rank
2:score
1
Set the student's rank:
B+
Set the student's xuefen:
5
Does any grade need to be added?
n
Set the student's ID number:
20181219
Set the student's first name:
Mary
Does student has second name?
n
Set the student's last name:
Clinton
Which types of grades you want to input:
1:rank
2:score
1
Set the student's rank:
C
Set the student's xuefen:
2
Does any grade need to be added?
n
Set the number of classes:
2
Class1 list:
--------------------
Name: Mary Clinton
ID: 20181219
GPA: 2
Name: William Jefferson Smith
ID: 20181201
GPA: 4.27
Class2 list:
--------------------
Name: James Bush
ID: 20181145
GPA: 3.5
小结
写这篇博客有感于看到的一个知乎问题:一个学校分班的问题,使用Java如果实现?
我把问题简化了,主要利用Arraylist可以追加对象的办法,把所有需要的信息都封装在对象里,以达到分配和后续更改的目的。当然,我的代码并没有处理异常情况以及输入错误的提示(太懒)。面向对象的好处是当需要处理大量复杂个个体时能比较有效的更改所需的个体信息,这个代码还可以继续完善:比如允许更改学生姓名、继续追加单个学生的成绩等等。
Github 源码