队员
黄腾飞 170327033
周静平 170327112
作业需求分析
- 使用文件录入20个部门,300个学生
- 部门含有以下属性:
1、 名称:单个字符串
2、 编号:单个字符串
3、 学生人数上限:单个数值
4、 特点标签:多个字符串
5、 多个常规活动时间段 - 学生含有以下属性
1、 姓名:单个字符串
2、 学号:单个字符串
3、 绩点:单个数值
4、 意愿部门:小于等于5个的多个字符串
5、 空闲时间段:多个字符串 - 进行智能匹配,智能匹配要求如下:
1、 代码规范
2、 为输入输出设计标准化、通用化、可扩展的接口
3、 使用不同优先级匹配 - 文件输出匹配结果,结果种类如下:
1、 已匹配结果
2、 未匹配部门
3、 未匹配学生 - 生成可执行的exe文件
- 结果分析
- 提交代码到Github
- 撰写博客
设计思路
- 配置文件定义输入输出文件以及优先级(可定义多个优先级)
- 编写生成输入文件的代码,模拟输入信息
- 获取部门和学生信息
- 按照志愿顺序进行匹配
1、 遍历所有学生(从i到n)
2、 遍历所有部门(从j到m)
3、 先按照i学生一志愿进行匹配
4、 i学生的志愿部门如果已存在匹配列表则加入匹配列表,否则建立一个部门对应多个学生的匹配列表
5、 一志愿匹配完毕后判断学生数是否达到上限,如果达到则进入下一个学生,否则,继续进入下一个志愿的匹配
6、 如果配置中存在一个或者多个优先级,遍历每个优先级,如果没有则进入第10步
7、 如果存在绩点优先则将匹配列表中的学生按照绩点排序,选取绩点前j部门学生人数上限的k个同学,如果k>j,匹配队列进入后续处理(第10步),否则标记学生为已匹配
8、 如果存在兴趣优先则按照学生兴趣与j部门的特点相同的个进行排序,类似绩点选取学生进行操作
9、 如果存在空闲时间优先,则类似兴趣优先进行操作
10、 将匹配数大于上限的匹配列表进行随机筛选部门上限个数的学生 - 打印匹配信息
- 优化接口
代码关键部分
部门类
public class Department {
private String departmentName; // 名称
private String departmentCode; // 编号
private Integer studentLimit; // 限制学生数[0-15]
private ArrayList<String> characteristics = new ArrayList<>(); // 特点标签
private ArrayList<String> routineActivityTime = new ArrayList<>(); // 常规活动时间
private boolean ismatch = false; // 是否匹配标识
...
(get和set函数)
}
学生类
public class Student {
private String studentName = null; // 姓名
private String studentCode = null; // 学号
private Float gradePoint = null; // 绩点
private ArrayList<String> interest = new ArrayList<>(); // 兴趣爱好
private ArrayList<String> departmentWishes = new ArrayList<>(); // 意愿部门
private ArrayList<String> freeTime = new ArrayList<>(); // 空闲时间
private boolean isMatch = false; // 是否已被匹配
private int sameInterestsNum = 0; // 爱好相同数
private int sametime = 0; // 空闲时间匹配数
private boolean ismatch = false; // 是否匹配标识
...
(get和set函数)
}
部门与学生的匹配类
/*记录一个部门匹配多个学生信息*/
public class D_S_Match {
private Department department; // 部门
private ArrayList<Student> students = new ArrayList<>(); //多个学生
private String studentStr = "/"; // 用于判断学生是否重复录入
...
(get和set函数)
}
监测匹配是否存在
/*监测匹配是否存在*/
try{
d_s_matches.get(j);
}catch (IndexOutOfBoundsException ioobe){
/*不存在则建立一个匹配*/
D_S_Match dsm = new D_S_Match();
departments.get(j).setIsmatch(true);
dsm.setDepartment(departments.get(j));
d_s_matches.add(dsm);
if (!d_s_matchesStr.matches("/"+departments.get(j).getDepartmentCode()+"/")){
d_s_matchesStr = d_s_matchesStr + departments.get(j).getDepartmentCode() + "/";
}
}
意愿匹配部门
// 志愿级别改变,判断人数是否够了
if(isChange && d_s_matches.get(j).getStudents().size()>=d_s_matches.get(j).getDepartment().getStudentLimit())break;
isChange = false;
/*意愿部门匹配部门*/
String[] dw = students.get(i).getDepartmentWishes().get(index).split("/");
if ((dw.length==1 && dw[0].equals(departments.get(j).getDepartmentName())) || (dw.length==2 && dw[0].equals(departments.get(j).getDepartmentCode()))){
if (!d_s_matches.get(j).getStudentStr().matches("/"+students.get(i).getStudentCode()+"/")){
d_s_matches.get(j).addStudents(students.get(i));
break;
}
}
使用内置快速排序算法
/*按绩点降序排序*/
private void sortByGradePoint(ArrayList<D_S_Match> d_s_matchesCopy){
for (int i = 0;i<d_s_matchesCopy.size();i++){
Collections.sort(d_s_matchesCopy.get(i).getStudents(), new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
return s2.getGradePoint().compareTo(s1.getGradePoint());
}
});
}
}
匹配类使用多构造函数
public DepartmentOfStudentMatchingImpl(){}
/*参数是否初始化*/
public DepartmentOfStudentMatchingImpl(Boolean goInit){
if (goInit) init();
}
匹配类初始化
/*初始化数据-获得部门和学生信息*/
public void init(){
if (config==null) config = new Config(true);
MatchIO matchIO = new MatchIO(config,true);
if (departments==null) departments = matchIO.getDepartments();
if (students==null) students = matchIO.getStudents();
}
接口
public interface DepartmentOfStudentMatching {
void init(); // 初始化-获得学生和部门
void matching(); // 进行匹配运算
void print(); // 打印匹配结果
<T> void othersPriority(T priority); // 其他匹配方式,使用泛型参数
void setConfig(Config config); // 设置配置文件
Config getConfig(); // 获得配置文件
ArrayList<Department> getDepartments(); // 获得部门信息
void setDepartments(ArrayList<Department> departments); // 设置部门信息
ArrayList<Student> getStudents(); // 获得学生信息
void setStudents(ArrayList<Student> students); // 设置学生信息
}
数据
配置文件数据
importfile[空格][输入文件地址]
outputfile[空格][输出文件地址]
priority(空格)(优先级)(空格)(优先级)(空格)(优先级)
生成的输入数据
生成的输出数据
算法测试报告
优先条件 | 匹配学生个数 | 未匹配学生个数 | 实际耗时(ms) | 输出文件路径 |
---|---|---|---|---|
绩点/兴趣/空闲时间 | 248 | 52 | 47 | E:web-appproject第二次结队作业IntelligentMatchsrcconfigoutput.txt |
兴趣/空闲时间 | 253 | 47 | 22 | E:web-appproject第二次结队作业IntelligentMatchsrcconfigoutput(1).txt |
绩点 | 218 | 92 | 28 | E:web-appproject第二次结队作业IntelligentMatchsrcconfigoutput(2).txt |
绩点/兴趣 | 240 | 60 | 25 | E:web-appproject第二次结队作业IntelligentMatchsrcconfigoutput(3).txt |
其中耗时只计算匹配时的耗时
程序优势
- 默认使用配置文件来设置输入输出文件以及优先级,有极大的灵活性
- 默认输入文件格式简单,方便输入
- 程序可以不使用文件而使用其他方式录入学生和部门信息,保留录入信息的接口
- 程序可以不使用文件而使用其他方式来录入配置信息
- 除了默认的4种匹配方式以外,还可以进行重写othersPriority(T priority)来增加匹配方式
总结感受
这次的作业相对于上次有较大的难度,上次只是进行原形的设计,需要的是大胆的想想能力和创造能力,这次主要需要的是代码能力和自身的基础积累。这次的作业,在两个人的沟通上,没有上次那么简单,除了基本逻辑之外,在代码上,对于自身写的代码,如果注释不够清晰明了,很难让对方读懂;同时对方的代码注释清晰明了,我也得花段时间捋一捋才能明白。不过还好的是,这些东西在实验室的项目上遇到过,也学了不少东西,在这里不是很大的坎。