结对项目第二次作业
一、结对成员
- 031502315 李芳凯
- 031502332 汪志彬
二、项目github地址
三、数据生成原理与考虑因素
- 我们生成的一组数据:戳这里(为了能比较直观,设置学生数为30,部门数为5;可通过修改代码参数,改变学生数量和部门数量)
- 数据生成原理:
- 学生数据:
- 学号(student_no):按顺序生成。以“031502”开头,从“001”开始依次增大
- 空闲时间(free_time):从周一到周日,通过随机数(0或1)判断当天是否产生空闲时间,产生则生成时间字符串加入时间列表;为满足空闲时间大于两个,若最终生成的列表小于等于二,则重新生成
- 申报部门(applications_department):先生成一个[1,5]之间的整数作为申请数量。然后随机生成一个数字对应部门的数字编号(判断是否重复生成,达到数量后退出)
- 标签(tags):将标签设置为一个枚举类型,遍历枚举对象,通过随机数(0或1),判断是否包含该标签,若包含则加入该生标签列表;若最终生成的列表小于等于二,则重新生成
- 部门数据:
- 部门号(department_no):按顺序生成。以“D”开头,从“01”开始依次增大
- 活动时间(event_schedules):与学生空闲时间生成方式相同
- 标签(tags):与学生的标签生成方式相同
- 人数限制(member_limit):采用随机数生成函数生成[10,15]之间的整数
- 学生数据:
- 考虑因素:此生成程序最主要的特点是考虑到了部门的热门程度(在微信群中看到了有人提出的80%的人选择20%的部门,觉得确实比较符合实际情况)。将热门的部门权重设置得大一点(实现方式是给比较热门的部门分配比较多个的数字,eg:若有五个部门,生成随机数字范围设置为[1,15],部门1分配[1,8],部门2分配[9,11],依此),部门权重可通过修改代码进行设置。其它考虑的因素就是活动时间不能太早,最早从早上8点开始,最晚24点结束(好像还是有点晚)。
四、数据建模及匹配程序的思路及实现方式
- 数据建模
本次作业遇到的第一个难点就是如何从json格式的txt文件中提取数据。最后通过搜索发现有一个比较好用的的外部jar包(gson2.7),并学习了gson包的使用,有了这个工具读取和输出都显得比较简单了。数据组织方式和json中大体相似。如下- Department
- department_no:部门编号
- List event_schedules:部门活动时间,是一个String类型列表
- List tags:部门标签,是一个String类型列表
- menber_limit:一个int类型,范围在[10,15]之间的整数
- isempty:bool类型,判断部门是否为空
- List member:是一个String类型的列表,存储纳入部门的学生学号
- Student
- student_no:学生编号
- application_departments:所申请的部门列表,是一个String类型列表
- List tags:学生标签,是一个String类型列表
- List free_time:部门标签,是一个String类型列表
- isadmitted:bool类型,判断是否有被录取
- Department
- 匹配程序
-
思路
具体的思路比较简单。站在部门的角度来选择学生,即每个部门依次去遍历学生列表,总共两轮,第一轮只录取没被其它部门录取的学生,第二轮则是符合要求即录取原因如下:
1、从头到尾遍历学生列表会对学号靠后的学生不公平,只录取未被录取的学生可以提高后面同学被录取的几率(虽然最后的结果还是不是很公平)
2、 部门正常也希望所录取的部员所加入部门尽可能少,这样才能在部门活动中投入较多时间- 第一次遍历纳新的步骤如下
1.若该学生尚未加入任何部门,则执行下一步。否则选取下一位学生,执行1
2.若学生的空闲时间是否与部门活动时间匹配,若有执行下一步。否则从学生列表里选取下一位,执行1
3.若学生有申请该部门,则执行下一步。否则从学生列表里选取下一位,执行1
4.若该生标签与部门匹配,则纳入该生。从学生列表里选取下一位,执行1 - 第二次遍历纳新步骤与第一次大体相同,但去除了步骤1,即第二轮符合条件即录取,不管该生是否已加入部门
- 第一次遍历纳新的步骤如下
-
实现方式
-
// 开始匹配,由部门招人,分两次,第一次招人优先招收未加入其它部门的人
for (ExDepartment exdepartment : ed) {
for (ExStudent exstudent : es) {
if(exstudent.isAdmitted())
continue;
if (isMatch(exdepartment, exstudent)) {
admitted(exdepartment, exstudent);
}
}
}
//第二次招人,符合要求即招入
for (ExDepartment exdepartment : ed) {
for (ExStudent exstudent : es) {
if(exdepartment.getMembers().contains(exstudent))
continue;
if (isMatch(exdepartment, exstudent)) {
admitted(exdepartment, exstudent);
}
}
private static boolean isMatch(ExDepartment exdepartment, ExStudent exstudent) {
// TODO Auto-generated method stub
if (timematch(exdepartment, exstudent)) {
for (String apt : exstudent.getApplication_department()) {
if (apt.equals(exdepartment.getDepartment_no())) {
return tagMatch(exdepartment, exstudent);
}
}
}
return false;
}
五、所遵循的代码规范(简单举例)
1、类名首字母大写
2、方法名首字母小写,采用驼峰表示法
3、内部字段采用private修饰,用getter与setter方法访问
4、包的导入,删除不用的导入,尽量不要使用整个包的导入。
六、结果评估
- 最终使用作业发布博客里面的input_data.txt的文件进行评测。
- 评测结果:
未被录取学生数:126
未录取学生的部门数:0 - 分析:最终获得的结果是大部分学生都能找到部门加入,大部分部门都能录取到一定的人数(10人以上),觉得应该算是录取率比较高的一种算法,主要优点也是能让更多人参与到部门活动中取。但是这种算法不足也非常明显,主要有以下两点
- 对于学号靠后的学生较为不公平(虽然已经尽量避免)
- 部门与学生之间的匹配较为宽松,即学生只要有填报该部门,至少符合有一个空闲时间与部门活动时间匹配,至少有一个标签与部门标签匹配,就有比较大可能被录用。这可能会导致部门因为人数限制没有录取到更合适的人(匹配程度更高的人)。
七、心得体会
- 个人收获
这次作业让我的国庆假期没有虚度,学到了很多新的知识。之前就有学过一点Java的基础知识,但是一直都没有运用的机会,这次作业应该算是初实践。做完这次作业让我在编码方面更加注重规范,能比较快的去解决异常问题。在本次作业过程中,get到的技能- 学会了如何引入外部jar包
- 学会如何将Java文件打包成exe文件
- 了解了json格式,并初步掌握如何使用工具包去处理json数据
- 结对感受
- 因为国庆我们两人都有回家,所以实际在一起编码的时间很少,但回家前我们一起商量了一下,大体敲定了用Java去写并讨论出了大体的匹配思路。回家后还是会经常使用QQ进行交流,例如一些匹配方法和一些在网上查找的资料,对友也给了我很多意见。因为对友在Java上处于初学状态,编码方面较为薄弱,所以我承担了比较大部分的编码任务,对友主要负责提出思路,发现细节和改进算法的思路。此次的结对非常愉快,我们互帮互助,共同进步。