结对成员
031502643 朱晓健
031502626 孙浩楷
GitHub项目地址
数据生成程序
input_data.txt
数据主要采用rand()来随机生成。通过相关措施来防止随机生成的重复数据,然后用Jsoncpp的Json::Writer输出。
考虑因素
- 部门总数为20个,学生总数为300个
- 时间段必须具有实际意义
- 防止部门号和学生号重复
- 作业要求中的其他点均要满足
在我们写数据生成程序的时候,遇到了生成的学号超过规定长度的情况,后来发现是一个地方过于粗心,没有对字符串清空。还有就是为了让unlucky_student和unlucky_department的数量尽量少,我们的free_time时间段是设的比较多的,event_schedule时间段是设的比较少的,但都满足两个以上的基本要求。
匹配程序
前序
看到题目的时候本来想直接从文本读入数据然后进行符号的识别与筛选,后来在上课的时候听到旁边两个同学正在讨论这次的结对作业,依稀听到了什么JSON格式输入很方便啊(心里一阵窃喜hahaha),虽然不知道JSON是什么,不过应该对这次的结对作业有帮助。
下课回去后,又认真地看了下题目,发现题目里赫然写着“Json格式”,如果我没猜错的话,我第一步要完成的工作应该就是把JSON格式的数据读到C++程序中。上网百度了一下需要安装jsoncpp,按照网上的教程死活装不上去,一直提示“link2005“”重定义错误,气的我有种砸电脑的冲动,折腾了我一早上。后来是在MSDN上看到的解决办法,在链接器的命令行中加入“ /FORCE:MULTIPLE ”,终于TM能用了。
数据建模
Student类的私有数据student_no,tags采用string类型,application_department采用动态string数组指针,并在析构函数中释放所申请的堆内存,free_time和department_no采用vector容器来存储。Department类的私有数据department_no,tags采用string类型,event_schedules采用动态string数组指针,member采用vector容器来存储。Student类和Department类互为友元类,方便成员函数的数据访问。
匹配程序思路
首先根据学生的部门意愿顺序来匹配,只要该学生的一个空闲时间段和该部门一个常规活动时间段匹配,该学生就能加入到该部门中;然后,再对所有部门进行扫描,如果发现部门人数超过限制人数的,则剔除兴趣标签不匹配的学生,直到部门人数等于限制人数为止,如果兴趣标签不匹配的学生都剔除完了部门人数仍然超过限制人数,则随机剔除,直到部门人数等于限制人数为止;对被剔除的学生再进行一次部门时间段匹配,以保证尽可能多的学生能分配到部门。
实现方式
- 首先利用Json::Reader将txt的字符流转换成Json::Value
- 使用函数Student::StuAssignment和Department::DepAssignment将Json::Value数据读入到各自的类私有数据中。
- 按照匹配原则使用Student::TimeMatch进行学生空闲时间段和部门常规活动时间段的匹配,匹配成功则加入该部门,并删除新成员相应的free_time,防止和后续的意愿部门时间冲突。
- 扫描每个部门的人数,若超过限制人数,则使用Department::InterestFilter函数对部门成员进行剔除,优先剔除兴趣标签不匹配的,直到人数等于限制人数,对被剔除的学生归还相应的free_time。
- 对被剔除的学生使用Student::Redistribute函数调用Student::TimeMatch函数进行匹配。
- 将相关数据写入Json::Value,使用Json::StyledWriter转换成字符流并输出。
写匹配程序时遇到的一些问题
- 本来是不想将两个类弄成互为友元类的,但是如果使用友元成员函数的话会引起循环依赖问题导致报错,在网上搜索了相关的解决方法并没有找到,只能声明为友元类了。
- 在最后的结果输出时,遇到了一点麻烦,示例中的输出是按照(unlucky_student,admitted,unlucky_department)的顺序进行输出的,但是我的程序不论怎么改,死活是按照(admitted,unlucky_department,unlucky_student)的顺序输出。在网上找了好久,后来发现因为jsoncpp是基于map容器,而map的key是按照字母顺序进行索引,如果要修改的话,要改STL,而且会导致map的算法效率下降。在咨询了助教之后,得知不按顺序也是可以的,于是便放弃了修改STL的想法。
代码规范
采用类来封装数据。变量名主要采用小写字母构成,单词与单词之间用下划线连接;函数名采用字母构成,单词首字母大写,单词之间没有使用分隔符。以Student类为例:
class Student
{
private:
std::string student_no;
std::vector<std::string>free_time;
int freetimes;
std::string *applications_department;
int applications;
std::string tags;
std::vector<std::string>department_no;
friend class Department;
public:
Student();
~Student();
void StuAssignment(Json::Value &root, int index);//将json数据读到Student类中
void TimeMatch(Department*dep,bool check);//进行时间匹配
bool UnluckyStudents();//判断一个学生是否一个部门都没被分配到
void FreetimeDelete(Department&dep);//对已分配到部门的学生删除相应的free_time
void Redistribute(Department&dep,Department*deps);//对被踢出的学生进行重新分配
friend int GetIndex(Student*stu, Department*dep, std::string s);//由部门号或者学生号获取索引
};
结果评估
按照上述的匹配原则,以示例中input_data.txt为例的话,有126个unluncky_student,0个unlucky_department。本次匹配原则并没有非常地严苛,只要学生空闲时间里的一个与部门活动时间段匹配即算匹配成功,因此unlucky_student相较于全匹配原则减少了很多。对匹配结果基本满意。
尤其是最后一个对被踢出的学生按照其部门意愿再进行分配我觉得很有必要,这样能够最大程度的保证每个学生能分配到部门。当然,如果空闲时间总是不和部门活动时间相匹配的话也只能成为UnluckyStudent了。
结对感受
这次的作业恰逢国庆,我回家了,浩楷在学校,无法面对面地进行交流,因此采用聊天工具QQ进行沟通。我们轮流进行编程,虽然没能出去玩,但是感觉这个国庆过得很充实。从浩楷身上学到很多项目经验。结对项目作业使我学到很多合作的经验,并且提高了我与人沟通交流的能力,使我受益匪浅,对我将来成为一个合格的程序员有很大帮助。虽然累了点,但是并不后悔当初选了软工实践这门课,到目前为止我真的学到了很多,这是以前其他课程所不能带给我的。