部门与学生的智能匹配的程序
结对成员:
170320053 林静
170327109 张梨贤
1.Github链接 link
2.输入数据
关键数据样例: (https://files.cnblogs.com/files/zlxbky/import.pdf)
考虑因素:
20个部门
部门编号(唯一确定值),部门编号先事先设定好,就把部门编号固定为A10000~A10019,下面学生的意愿还要用到,所以用一个字符串数组存起来;
部门需要的学生数上限:由于限定范围在0~15,所以就是直接随机产生0~15的一个随机数;
部门的特点标签:事先设定多个标签,用数组存起来。生成部门对象时,随机生成3个0-便签数组之间的不重复的数字,在根据数字作为数组下标到标签数组里面找到该标签并输出。
部门常规活动时间:这个的处理方式跟标签类似。考虑到实际情况,部门的活动时间大多是在“10:30~11:30”,“16:30~18:00”,“20:00~21:30”三个时间段,所以我们先预设了21个时间段,一周7天,每天三个,共21个,并用数组存起来。随机生成3个0-时间数组之间的不重复的数字,在根据数字作为数组下标到时间数组里面找到该时间并输出。
300个学生
部门编号(唯一确定值):学生编号先事先设定好,就把学生编号固定为1703271000~1703271299,用一个字符串数组存起来;
绩点成绩,单个,数值(随机生成一个0-10之间的浮点类型数值);
兴趣标签,多个,字符(学生的兴趣标签一定是所有部门特点标签里面的)
意向志愿,每个学生有不多于5个的部门意愿(不能空缺);
空闲时间段,多个,字符。
- 部门
部门编号:部门编号唯一,从A10000到A10019
部门需要的学生数上限:限定范围定为0-15,即随机产生0-15中的一个数字
部门的特点标签:生成部门对象时,随机生成3个0-便签数组之间的不重复的数字,在根据数字作为数组下标到标签数组里面找到该标签并输出。
部门常规活动时间:随机生成3个0-时间数组之间的不重复的数字,在根据数字作为数组下标到时间数组里面找到该时间并输出。
- 学生
学生编号:学生编号唯一,学生编号先事先设定好,就把学生编号固定为1703271000~1703271299,用一个字符串数组存起来;
学生名字:从姓氏数组中随机产生一个姓,以及从名字数组中随机产生两个字,组合成名字。
绩点成绩:随机生成绩点成绩,从高到低排序,当意愿相同时优先考虑绩点高的学生
兴趣标签:在生成学生对象时,随机生成3个不重复的兴趣标签。
部门意愿:在生成学生对象时,随机生成1-5个部门意愿。
空闲时间段:在生成学生对象时,随机生成3个不重复的空闲时间段。
3.匹配算法
数据模型
类图
流程图
算法匹配过程
- Step1:生成300个学生对象(其中包含学号,姓名,兴趣标签,空闲时间段等基础数据)和部门对象(其中包含部门编号,部门标签,常规活动时间段)。
- Step2:为了不让后生成的学生的优先级过低导致不能进入部门,首先根据绩点进行从高到低进行排序,绩点高的有优先选择权。
- Step3:在第二步的前提下,以第一志愿优先原则:遍历其第一志愿,当第一志愿对应的部门的人数没有满的情况下,进行匹配判断,匹配判断分为以下两步:
- Step 3.1 进行时间判断,将学生的空闲时间段与部门的常规活动时间段进行匹配,当三个时间段中有1个时间段互相匹配,进行下一步判断。
- Step 3.2 时间判断满足的情况下,进行标签匹配。将学生的兴趣标签与部门的标签进行一一对比,当3个兴趣标签中有1个互相匹配,即满足判断,更新学生信息与部门信息(学生:加入部门信息、加入部门数 部门:成员信息、部门人数、部门人数上限等。
- Step4 对所有的学生,依旧按照成绩排名遍历其所有志愿,当其志愿对应的部门的人数没有满的情况下,进行匹配判断,匹配判断分为以下两步:同上。
- Step 5 直到遍历完所有学生的所有部门意愿为止,匹配算法截止。
结果分析
部门纳新比例稳定在70%左右。因为纳新部门人数是随机生成的,所有每次的数据量不同,录取比例基本稳定在70%左右。
条件 | 学生人数 | 部门纳新人数 | 加入学生数 | 部门招收比例 | 输出匹配学生文件路径 | 输出匹配部门文件路径 |
---|---|---|---|---|---|---|
绩点+时间+标签 | 300 | 119 | 81 | 68% | https://files.cnblogs.com/files/zlxbky/output_conditionS.pdf) | https://files.cnblogs.com/files/zlxbky/output_conditionD.pdf) |
4.关键代码解释
- 实体类(entity)
- 全局类(global)
- 方法类(method)
- 程序入口(main)
实体类(学生类和部门类)
/*学生实体类*/
private String St_id; //学号
private String St_name; //名字
private float St_grade; //绩点
private int [] St_volunter = new int[5]; //学生志愿
private String [] St_interest=new String [5]; //兴趣标签
private String [] St_time=new String [5]; //可用时间段
private List<Dept> myDept = new ArrayList<Dept>(); //当前学生所在部门
/*部门实体类*/
private String Dept_id; //部门编号
private String [] Dept_tags=new String [5]; //部门标签
private String [] Dept_time=new String [5]; //部门时间
private int Dept_num; //部门人数
private List<Student> myStudent = new ArrayList<Student>(); //当前部门下的学生
生成学生和部门对象的程序
/*生成学生对象*/
public String createSid(int i){.....}//生成学生学号
public String createSname(){....}//生成学生名字
public int[] creatVolunter(){....}//生成学生部门志愿数组
public float createGrade(){....}//生成学生绩点
public String[] createStime(){....}//生成学生空闲时间
public String[] createStags(){....}//生成学生兴趣标签
public List<Student> createAllStudent(String Sid[],Float SGrade[]){....}//生成学生对象列表
/*生成部门对象*/
public String createDid(int i){.....}//生成部门编号
public String[] createDtime(){....}//生成部门常规活动时间
public String[] createDtags(){....}//生成部门标签
public List<Dept> createAllDept(){....}//生成部门对象列表
全局类
public class Global {
public static List<Student> studentList;
public static List<Dept> deptList;
public static List<Student> tempdeptList;
public static Map<Float,String> map;
}
对绩点进行排序
/*对学生绩点进行降序排序*/
public class SetStudentGrade {
public static Map<Float,String> setStudentGrade( ){
Map<Float,String> map = new TreeMap<Float,String >(
new Comparator<Float>() {
public int compare(Float obj1, Float obj2) {
// 降序排序
return obj2.compareTo(obj1);
}
});
for (int i = 0; i < Global.tempdeptList.size(); i++) {
String id = Global.tempdeptList.get(i).getSt_id();
map.put(Global.tempdeptList.get(i).getSt_grade(),id );
}
return map;
}
}
匹配方法
public class Matching {
public static void allocteStudent(int round) {.....}
}
输出工具类
public class PrintUtils {
//打印所有的学生对象
public static void printStudent(List<Student> stulist) throws IOException {....}
//打印所有的部门对象
public static void printDept(List<Dept> deptlist,int d_num[])throws IOException{....}
//打印部门纳新总人数和匹配人数
public static void printNum(List<Dept> deptlist,int d_num[])throws IOException{....}
//打印匹配好的学生对象
public static void printStudentDept(List<Student> studentList)throws IOException{....}
结对感受
由于上一次的结对作业仅仅是原型设计,实现起来可谓是尽情发挥自己的想象力了。然而这次涉及到真正的代码实现,那就产生了较大的难度了。首先,结对作业给我很大的感觉就是要提前规划好个人的分工,不然到了最后会手忙脚乱。其次,要注意代码的规范性问题。结对作业不比个人项目,只要自己看懂就好了,结对作业可能需要你适当的写上注释必要时候可能还需要文档吧。不然看对方的代码真的又耗时又痛苦。而且,结对作业不比个人项目,个人项目由于缺少了那份团队意识感,可能会相拖沓,而结对作业会催促着你早点完成自己的部分不要拖队友的后腿。其实这样的结对编程在实验室项目当中已经有所体验了,所以在实施上没有遇到特别大的难度。