结对第二次作业

高级软工结对第二次作业

github项目地址

需求分析

本次结对项目对最终程序的功能要求如下:

编码实现一个部门与学生的智能匹配的程序。
实现一个智能自动分配算法,根据输入信息,输出部门和学生间的匹配信息(一个学生可以确认多个他所申请的部门,一个部门可以分配少于等于其要求的学生数的学生) 及未被分配到学生的部门未被部门选中的学生

本项目的关键在于设计一个智能匹配算法,该算法主要实现根据输入的学生和部门数据,输出符合部门要求的匹配名单。现从部门角度做出如下需求分析:

  • 优先考虑将本部门作为第一部门意愿的学生
  • 优先考虑空闲时间段和本部门常规活动时间段相符程度大的学生
  • 综合考虑学生空闲时间与本部门常规活动时间符合度、兴趣标签与本部门特点标签符合度、绩点高低

数据模型

模型的分析与建立

根据需求分析建立如下数据模型:

  • 部门数据模型:
字段 数量(个) 类型
部门名称 1 字符
人数上限 1 数值
特点标签 1-5 字符
常规活动时间 1-5 字符
录取学生名单 1 字符

注:其中录取学生名单 字段取值由匹配算法产生

部门数据模型样例:

部门名称 人数上限 特点标签 常规活动时间 录取学生名单
活动部 14 看电影,跳舞 Sun,20:30,21:00;Tue,19:30,20:00;Fri,20:30,23:00 沈剑伸,杨伸世
  • 学生数据模型:
字段 数量(个) 类型
学号 1 字符
姓名 1 字符
绩点 1 数值
意愿部门 1-5 字符
意愿部门数 1 数值
未匹配意愿数 1 数值
兴趣标签 1-5 字符
空闲时间 1-5 字符
各部门综合得分 1-20 数值

注:其中意愿部门数未匹配意愿数各部门综合得分 字段取值由匹配算法产生

学生数据模型样例:

学号 姓名 绩点 意愿部门 意愿部门数 未匹配意愿数 兴趣标签 空闲时间 各部门综合得分
170312369 沈剑伸 1.07 策划部,权益部,客服部,外联部 4 0 策划,乒乓球,学习 Fri,22:30,23:30;Sat,19:30,20:00 25.07,30,26,28

注:由于时间段为随机产生,为避免部门常规时间与所有学生的空闲时间都无法匹配的情况,将时间段限制在19:00-23:00

代码规范

规定在编程过程中须严格遵循以下规范:

  • 对于代码的各个功能和参数进行了详细注释
  • 变量以及函数命名的规范:使用驼峰命名法进行命名
  • 使用类来封装面向对象的概念

代码佐证如下:

class Department
{
public:
	Department(string name, string limitNum, string feature, string normalDate)
	{
		setLimitNum(limitNum);
		setFeature(feature);
		setNormalDate(normalDate);
		setName(name);
	}
private:
	string name;   //部门名称
	int limitNum;  //人数上限
	int existing;  //已选人数
	vector<string> feature; //特点标签
	vector<vector<float>> normalDate;    //常规活动时间
	vector<Student> stuList;//创建被录取学生名单
public:
	void setLimitNum(string limitNum);
	void setExisting();
	void setFeature(string feature);
	void setNormalDate(string normalDate);
	void addMember();
	void setName(string name);
	string getName();
	int getExisting();
	int getLimitNum();
	vector<vector<float>> getNormalDate();
	vector<string>getFeature();
	friend vector<float> timeCut(string normalDate);
	friend vector<string> slice(string s, const char* b);
	void setStu(Student s);
	vector<Student> getStu();
};

匹配算法

算法描述

  • 遍历所有学生的第i(1-5)志愿部门并计算第一志愿对应的部门综合得分
  • 以第i(1-5)志愿得分为依据进行降序排序后进行录取(将录取学生加入录取学生名单)
  • 循环执行以上步骤直到所有部门录取人数达到上限(每个部门最多15人)或所有学生志愿(每个学生最多5个)均已计算过得分

算法流程如下图:

算法分析

本算法结合部门需求,从实际出发,模拟现实生活中部门招新过程,即每个部门最先匹配的是第一志愿填报本部门的学生,根据学生信息进行评估录取,若录取人数未达到上限则进行第二轮录取,即开始遍历学生的第二志愿。即考虑以下两条原则:

  • 志愿优先
  • 综合得分优先

关键代码

匹配算法的关键代码如下:

void Match::start()
{
	//遍历5个志愿
	for (int i = 0; i < 5; i++)
	{
		//学生对象遍历
		vector<Student>::iterator stuIter = stu.begin();
		while (stuIter != stu.end())
		{
			//匹配学生第i志愿部门,进行对应的匹配评分
			string intent = stuIter->getIntentDepart()[i];
			if (intent == "")
			{
				stuIter->setNotMatch();
				matchOver.push_back(*stuIter);
				stuIter = stu.erase(stuIter);
				continue;
			}
			vector<Department>::iterator Iter = dep.begin();
			//查找到学生第i志愿部门对象
			while (Iter != dep.end())
			{
				Iter->getName();
				if (Iter->getName() == intent)
				{
					break;
				}
				Iter++;
			}
			//将绩点作为成绩的一部分算入匹配分数
			stuIter->changeMark(intent, stuIter->getGpa());
			//如果学生空闲时间和部门活动时间完全不匹配则分数归零,匹配下一学生的志愿
			timeMatch(*stuIter, *Iter);

			//匹配兴趣标签并打分
			tagMatch(*stuIter, *Iter);
			//学生未匹配志愿减一
			stuIter->setNotMatch();
			stuIter++;
		}
		vector<Department>::iterator depIter = dep.begin();
		//在第i个志愿下,按照不同部门对学生分别进行分数排序,取出每个部门对应的成绩非零的同学加入部门
		while (depIter != dep.end())
		{
			order(stu, depIter->getName());
			stuIter = stu.begin();
			while (stuIter != stu.end())
			{
				if (depIter->getExisting() == depIter->getLimitNum() || !stuIter->getMark(depIter->getName()))
				{
					stuIter++;
					continue;
				}
				depIter->setStu(*stuIter);
				stuIter->setMarkZero(depIter->getName());
				depIter->setExisting();
				stuIter->setAccess();
				//如果学生所有志愿完成匹配,则转移学生对象至matchOver容器
				if (!stuIter->getNotMatch())
				{
					matchOver.push_back(*stuIter);
					stuIter = stu.erase(stuIter);
				}
				else
				{
					stuIter++;
				}
			}
			depIter++;
		}
	}
}

结果分析评价

测试报告

根据以上算法形成的算法测试报告如下:

优先条件 匹配学生个数 未匹配学生个数 实际耗时(s) 输出文件路径
志愿优先 192 108 29.313 文件路径

性能分析

性能分析结果如上图所示,排序占用了93.60%的时间,不出意外的占用了大部分时间,因为这里采用了冒泡排序的方法。如果改进排序方法,程序性能可能取得进一步的提升。

结果分析

该算法对于不同优先条件变更的适应能力很好,对于不同的优先条件,我们只需要调整对应条件的评分权重,使该条件的得分足够大即可,所以改动也只需要几分钟而已。

结对感受

林翔的结对感受

林翔的结对感受:本次的作业极大的锻炼了我的代码能力。在与李明皇的结对过程中,感受到了他的认真严谨的态度。在设计算法模型和敲代码时我们经常发生争论,但是最后都能很好的解决问题。

李明皇的结对感受

本次结对项目所给的时间有点紧,还好这几天课比较少,不然可能完成不了。时间主要花在了算法设计和最后的debug上。
以前对C++的实践主要停留在做题的层面上,在真正的编程中发现了在题目中学不到的东西,比如代码的规范性对编程效率起到了很大的作用,好的规范会使代码review事半功倍。
队友林翔在结对编程中很给力,他的逻辑思维一直很清晰,对于整个算法的把握了然于胸,能够很快的想到我没有考虑的地方并给出解决方案。

原文地址:https://www.cnblogs.com/liminghuang/p/7726901.html