软件工程实践:结对作业(第二次作业)
作业地址
结对成员
Github
- Deputy: Department-to-Student bidirectional selection;
- Deputy-generator:generate corresponding input JSON file for Deputy.
数据生成程序, Deputy-generator
一个生成的数据:input_data.json.
数据生成原理
部门:
1.部门编号;
2.部门纳新上限;
3.部门固定活动时间;
4.部门的兴趣标签
学生:
1.学号;
2.选择的部门;
3.业余时间;
4.兴趣标签;
5.是否被部门选中
生成过程:
学生:
(第一步:生成除部门意愿以外的基本信息)
- 按序生成学生学号(001-300);
- 对于每一个学生,生成总数在范围[2, 8]之间的空闲时间段,分布一周7天,每个空闲时间段不超过3个小时,空闲时间段开始时间在[480, 1260],即早上八点到晚上九点之间;避免一天之内的空闲时间段的重叠,方法是将之前的时间段作为约束来生成下一时间段;
- 随机选择兴趣标签数目,不作约束;
- 生成数量在范围[1, 5]之间的部门意愿数目。
(第二步:生成部门意愿)
-首先生成热门部门的数量,经过商量确定为i【24】个,热门的占比为10,剩下的普通部门占比为4,这样我们就可以的到区间为【010i+4(20-i)】(作用在后面体现)
-然后生成该学生一共选k个部门(k的范围是【1~5】)
-最后依次生成k个部门,生成的方法是生成一个随机数,其范围是【0~10i+4(20-i)】(从第一步可以得到),然后根据生成的数我们就可以推出时选哪个部门,同时我们会生成一个数据用来存储前面选过的部门,避免重复选择。
部门:
- 按序生成部门编号(01-20);
- 对于每一个部门,生成总数在范围[2, 5]之间的空闲时间段,分布一周7天,每个空闲时间段不超过3个小时,空闲时间段开始时间在[480, 1260],即早上八点到晚上九点之间;避免一天之内的空闲时间段的重叠,方法是将之前的时间段作为约束来生成下一时间段;
- 随机生成范围在[10, 15]之间的人员限制;
- 选择数目在[2, 5]之间的兴趣标签。
考虑的因素
1.热门部门的占比不同,会有更多的人去报名该部门。
2.一周之内部门的活动时间最多不超过5次,每一天的活动次数不超过2次,每一次的活动时间不超过3个小时。
3.学生的兴趣标签可以比较多,因为现在学生的特长更加广泛,但是部门的标签不能太多,因为部门本身就有自己的特色,倾向,这已经使其标签范围不可能太广。
4.部门的活动时间是早上八点到晚上九点(符合实际,不可能大清早去活动)
5.每个人分配一到两个部门,这样更加符合学生的实际状况,不会太过劳累,
数据建模及匹配程序的思路及实现方式
数据建模
部门选择学生要考虑三个因素:学生选该部门是第几个志愿(同时也要考虑学生一共有几个志愿),学生兴趣标签和部门标签的匹配程度,学生的业余时间和部门固定活动时间的匹配程度。
第一个因素(学生选该部门是第几个志愿(同时也要考虑学生一共有几个志愿)):
显然越前面的志愿分值越高,学生选的志愿越少分值也会越高,同时为了使志愿之间的占比不是线性的(因为线性的区分度太低),这里就采用了取平方的方法。而学生志愿越少得分越高则想到了利用倒数的方法,而经过多次计算不同的值得到的结果,确定分子为2的时候,结果比较满意。
所以得到这部分的计算公式:
value1=(2/student_instance.applications_department_number)(5-k)(5-k)
(其中student_instance.applications_department_number就是学生总得志愿数,k是该志愿是学生的第几志愿)
第二因素(学生兴趣标签和部门标签的匹配程度):
学生与部门标签的匹配度乘上某个数就是该部分的得分,而考虑了第一因素,发现第一因素的最高分为50,所以给第二因素的常量也为50。
所以得到这部分的计算公式:
value2=(match_tags/department_instance.tag_number)*50
(其中match_tags是学生与部门标签的匹配的条数,department_instance.tag_number是部门总的标签数)
第三因数(学生的业余时间和部门固定活动时间的匹配程度):
根据现实情况,学生的业余时间越多越好,这样部门能更好的管理部员,而这个因素不能占太多的比重,毕竟头两个因素才是重点,所以这个因素是用来当做附加分的,分值也不高,大概在5分左右。
所以得到这部分的计算公式:
value3=times*stu_weekday_num/dep_weekday_num
(其中times是学生与部门的时间匹配数,stu_weekday_num是学生的课余时间总数,dep_weekday_num是部门的固定活动时间总数)
因此我们可以知道匹配值value=value1+value2+value3
匹配程序的思路及实现方式
具体方法定义看:matchAlgorithmTools.cpp
具体实现过程看:matchAlgorithm.cpp
下面是对过程的一个步骤分解
第一步:
将学生分为两类(有选志愿的和没选志愿的)
调用matchAlgorithmTools.cpp的void deliverStudent()函数
第二步:
记录部门被学生选择的次数(分为0~4个志愿)
(其中currentDepartment是当前部门,k是第几志愿)
第三步:
计算学生的权值(用于部门选择学生)
调用matchAlgorithmTools.cpp的
int matchedLevelValue(int k, students student_instance, departments department_instance)函数
第四步:
将部门按照受欢迎程度进行排序(之后热门部门将优先选择学生)
调用matchAlgorithmTools.cpp的void calculateDepOrder()函数
(计算的数组是由第二步得到algorithmTool.studentWishes二维数组)
第五步:
部门选择学生
根据学生的value排序,拿出前department[currentDepartment].member_limit(就是部门收取人数的上限)个没被其他部门选走的学生加入当前的部门,完成分配。
代码规范
本次项目统一使用Github进行源代码管理,两人统一使用Wasdns账号进行提交。我们在结对过程中遵循以下规范:
- 1.良好的注释习惯:对于每一个代码模块(一行或者多行,函数或者类)都进行详细的注释,保证队友能够理解
- 2.参考"驼峰命名法"对变量进行命名,要求每一个变量的命名都是有意义的,且能够清楚地通过变量名了解该变量的作用
- 3.进行异常的判断及处理
代码佐证:
/*
* The following codes are used to:
*
* 1.update studentWishes to calculate the order among departments.
*
* 2.calculate studentDepValues(student vs department) to find out
* that if the student is matched against the department or not.
* And for the following codes(i.e.L79), the studentDepValues is
* used to help the department choose students.
*
*/
for (int i = 0; i < algorithmTool.eagerStudentNumber; i++) {
// current index of eagerStudents
int currentStudent = i;
// the total number of departments
// that chosen by the current student
int depTotal = algorithmTool.eagerStudent[currentStudent].applications_department_number;
// j: the number of departments
// k: the number of student wishes
// for each of the departments
for (int j = 0; j < 20; j++) {
int currentDepartment = j;
// the number of current department
string currentDepartment_str = department[currentDepartment].department_number;
// check if the department
// is the chosen one or not
for (int k = 0; k < depTotal; k++) {
// the k wish of current student
string kwish = algorithmTool.eagerStudent[currentStudent].applications_department[k];
// if matched, means that
// the student want this department
if (kwish == currentDepartment_str) {
// add 1 to studentWishes[department_number: currentDepartment][wishes: k]
algorithmTool.studentWishes[currentDepartment][k]++;
// calculate the value between current student
// and current department based on k
// (the current number of wishes), the student instance
// and the department instance
int stuDepValue = algorithmTool.matchedLevelValue(k, algorithmTool.eagerStudent[currentStudent], department[currentDepartment]);
assert(stuDepValue != -1);
// record the stuDepValue
// calculated by matchedLevelValue(...)
// in studentDepValues[student_instance_index][department_instance_index]
algorithmTool.studentDepValues[currentStudent][currentDepartment] = stuDepValue;
break;
}
}
}
}
结果评估
运行了助教给的输入样例,结果如下:
- 1.未匹配人数:190人,占比63%;
- 2.未匹配部门:2个,占比10%;
- 3.部门最多招纳人数:10人;
- 4.部门平均招纳人数:5.5人。
通过估算,平均每个部门收人上限为10~15个,最多要收取240人左右,而我们运行的结果显示有110人被部门收走,也就是收取人达到百分五十左右,去除和部门不匹配的人,百分五十是可以接受的数据。
结对感受
(1)结对感受:
李鸣:这次结对作业,刚好我和我翔(队友)都是莆田人,所以就算是国庆放假也能够面基结对,整个国庆我们面基了5次,同时还语音结对了3次,可以说是整个国庆都是在结对中度过了,基本上也没消停过,说实话是很难受,毕竟是今年的最后一个法定节假日。但是,在和我翔的结对中也不乏乐趣,经我翔介绍发现了一家很有情趣的咖啡馆,听我翔说买上一杯咖啡可以在这度过一个下午,结对的过程中有让我印象最深的就是我翔的代码规范,真的做的很好,比起我的一团糟代码简直天差地别,这也让我明白了代码规范的重要性,在作业刚开始的时候我翔就自己做好了输入输出的工作,而我的工作主要就是想如何匹配,其他的部分则是我们一起思考,敲代码弄好的,这过程中也发现了结对带来的一个好处就是,敲代码的人头脑可能不会那么清晰,有时候一些小错误发现不了,而一旁的队友一般都会很容易发现这种小错误,节省了很多的时间。总得来说,这次结对是一次不错的体验,唯一的代价估计就是少了个国庆。
陈翔:我能够深深体会到这两次结对的作业量,在多件事情并行的情况下国庆假期等于没放假了。这次结对,几天内近几k行的代码量,近百余次的Github项目管理记录(不算什么但是我觉得还是要列一下:D),和我鸣多次的电话讨论确定算法模型,见面敲定解决方案。虽然不是第一次和别人合作完成项目,但是本次结对依然获益颇多:一是收获了结对编程的经验,有旁边人实时code review的感觉还是很良好的,因为一个人的时候经常是这种情况:"写bug五分钟,debug两小时",在结对编程中就不会有这种情况的发生,避免了大量不必要时间的浪费,提高了整体效率,此外作为一个小团队也学习了一些团队协作的知识,比如编码规范,模块对接等等;二是充实(填满)了整个假期,提升了整体的编码水平,巩固了(再一次预习了)C++的知识,让我了解到很多Linux下编译、编程的知识以及之前未曾涉及到的JSON的解析方法;三是在结对过程中与我鸣多次交流结下了深厚(?)的友谊,虽然不时会被他和他的小可爱虐一脸,可是他幽默风趣、细心可爱、阳光帅气、有担当负责任,是一个不可多得的好搭档,编码过程中思路清晰,纠正了我不少的问题。
我对于我鸣的建议有以下两点:
- 1.编码过程中要时刻注意写注释和代码规范,变量命名时要合理清晰;
- 2.Github commit的习惯,当你上手学会了Github之后,它会是一个非常棒的工具;
3.好好珍惜女朋友,工作的时候女朋友的电话还是要接的。
贴上我翔拍摄的咖啡馆(搞基好去处):
以及店内一只猫(阿布,可撸!!),看见我的电脑包就坐上去了????