结对编程作业——毕设导师智能匹配

结对编程作业——毕设导师智能匹配

031402317 李佳恺
031402511 黄家俊

问题描述及要求

  • 输入30个老师(包含带学生数的要求的上限,单个数值,在[0,8]内),100个学生(包含绩点信息),每个学生有5个导师志愿(志愿的导师可以重复但不能空缺),要求另外写生成程序随机实现

  • 实现一个智能自动分配算法,根据输入信息,输出导师和学生间的匹配信息(一个学生只能有一个确认导师,一个导师可以带少于等于其要求的学生数的学生) 及未被分配到学生的导师和未被导师选中的学生,要求输出的未被导师选中的学生人数越少越好。

  • 为输入输出设计标准化、通用化、可扩展的接口,为该智能匹配程序模块后期可能的整合入系统提供便利

  • 输入输出的格式,如采用文本文件或数据库的方式输入,可自由讨论确定,但需要明确,为后期可能的整合入系统提供便利

  • 需要为智能匹配算法确立几条分配或排序原则,比如 绩点优先、或其他、或其他等等

编程语言:JAVA

模块设计

  • 实体类(entity)

  • 全局类(global)

  • 方法类(method)

  • 测试类(test)

学生类和导师类的定义

/**学生实体类**/
public class Student {private String sName; // 学生姓名private float gradePoint; // 学生绩点private int[] sapplication = new int[5]; // 学生志愿private int teacherId; // 已选中老师编号
/*** 教师实体类**/
public class Teacher {private int tId;  //教师编号private String tName;  //教师姓名private int sectionMax;  //区间最大值private int sectionRest;  //剩下人数    private List<Student> myStudent = new ArrayList<Student>(); //当前老师下的学生

生成程序代码实现

1. 采用JAVA的random()函数在字符串区间中随机选择5个字符生成学生或导师的姓名

 //生成学生随机姓名,教师姓名方法一样public String createStudentName(){     String stringBase = "abcdefghijklmnopqrstuvwxyz";Random random = new Random();StringBuffer studentName = new StringBuffer();     for (int i = 0; i < 6; i++) {     int number = random.nextInt(stringBase.length()); studentName.append(stringBase.charAt(number));     }     return studentName.toString();          
}

2. random()函数可以产生[0,1]区间的小数,利用其随机产生[1,5]区间的浮点数作为学生绩点

//产生学生的绩点
public float createGradePoint(){Random random = new Random();float gradePoint = random.nextFloat()*4+1;gradePoint =  (float) ((int)((gradePoint*100+5))/100.0);//取小数点后两位return gradePoint;
}

3. 随机产生[1,30]区间的整数作为学生志愿(整数对应导师的Id)

//产生学生的志愿
public int[] creatApplication(){int[] application = new int[5];Random random = new Random ();  boolean[]  bool = new boolean[30];  int randInt = 0;  /**得到5个不同的随机数*/  for(int i = 0; i < 5 ; i++) {  do{  randInt  = random.nextInt(30);  }while(bool[randInt]);   bool[randInt] = true; application[i]=randInt+1;}return application;
}

4. 随机产生[0.8]区间的整数作为老师带学生数的上限

//产生区间上限
public int createSectionMax(){Random random = new Random();int sectionMax = random.nextInt(8);return sectionMax;
}

5. 定义集合来储存100个学生和30个导师(setXXX()方法在学生类和导师类里面定义,用于学生或导师的信息的初始化,另创建class文件定义集合的全局变量)

//产生学生对象
public List<Student> createAllStudent(){CreateMember cm = new CreateMember();List<Student> studentList= new ArrayList<Student>();for(int i=0;i<100;i++){Student s = new Student(); s.setsName(cm.createStudentName());s.setGradePoint(cm.createGradePoint());s.setSapplication(cm.creatApplication());s.setTeacherId(0);studentList.add(s);}return studentList;
}//产生教师对象
public List<Teacher> createAllTeacher(){CreateMember cm = new CreateMember();List<Teacher> teacherList= new ArrayList<Teacher>();for(int i=1;i<=30;i++){Teacher t = new Teacher();t.settId(i);t.settName(cm.createTeacherName());int temp = cm.createSectionMax();Global.countAll+=temp;t.setSectionMax(temp);t.setSectionRest(temp);teacherList.add(t);}return teacherList;
}

匹配算法思想以及代码实现

  • 志愿优先原则,五轮匹配,每轮从选择学生上限未满的导师Id出发,每个导师可以匹配到若干个当前轮次n,学生第n志愿是该老师Id的局部学生集合,并从集合中选择学生

  • 考虑到在上述匹配到的局部学生集合当中学生应当有个排序以实现老师从中筛选出排名靠前的学生,于是这个排序就非常重要

  • 我们知道每个导师的热门程度不同,因此我们定义学生未满的导师有一个热度值heat,并在每轮匹配算法的开始更新heat值,我们先遍历当前轮次全部学生的集合(在代码当中我们是从全部学生的集合当中删掉每轮被选中的学生),得到每个导师共有几个选他的学生sum,然后求出heat=sum/sectionRest(sectionRest为当前轮次老师剩余的选择学生上限)

//设置教师热度值
public class SetTeacherHeat {public void setHeat(){//遍历还在参加选择的教师for(Teacher teacher : Global.teacherList){//累计当前教师此轮的热度值float heat = 0;//遍历还在参加选择的学生for(Student student : Global.studentList){//存储学生志愿int[] tempValue = student.getSapplication();//当学生志愿与当前教师编号,不重复志愿for(int i=0;i<5;i++){if(teacher.gettId()==tempValue[i]){heat++;break;}                   }   }//设置当前教师的热度值heat=heat/teacher.getSectionRest();teacher.setHeat(heat);                  }}}
  • 定义学生有一个综合值composite,每轮匹配算法开始的时候更新其值,其值为该学生绩点gradePoint * g + 该学生剩余志愿导师热度值之和 * v,根据该值进行当前导师的局部学生集合的学生排序。老师选择学生的时候看的是学生的绩点,但是为了让更多的学生能够选到导师,我们认为可以看每个学生选的导师的热度值之和,热度值高代表其竞争压力大,综合绩点和热度值来进行排序。其中g + v = 1 ,其比例我们经过多次测试为g=0.5.v=0.5最为合理。

//获得此轮当前学生临时综合值
public class GetTempComposite {public float getComposite(Student student,int round){//获得学生志愿int[] tempValue = student.getSapplication();//记录学生此轮综合值int tempComposite=0;//变量此轮及之后学生志愿所选教师的热度        for(int i=round;i<=round;i++){//志愿不重复,找到相符就跳出for(Teacher teacher : Global.teacherList ){//当前志愿与教师id相符if(tempValue[i]==teacher.gettId()){//累加tempComposite+=teacher.getHeat();break;}               }       }       return tempComposite;}}
    //更新学生综合值,系数比例g,v;for(Student student : tempStudentList){GetTempComposite gtp = new GetTempComposite();float tempComposite = 0;tempComposite = gtp.getComposite(student, round);float composite=0;float gradePoints=0;gradePoints = student.getGradePoint();composite=gradePoints*g+tempComposite*v;        student.setComposite(composite);}
    // 实现学生按综合值从大到小排序class SortByGradePoint implements Comparator {public int compare(Object o1, Object o2) {Student s1 = (Student) o1;Student s2 = (Student) o2;float temp1=s1.getComposite();float temp2=s2.getComposite();if (temp1 < temp2)return 1;else if (temp1 == temp2) {return 0;}return -1;}}
  • 进行第n轮匹配:

    1. 设置教师列表迭代器来遍历导师集合
    // 设置教师列表迭代器Iterator<Teacher> teacherIterator = Global.teacherList.iterator();

2. for循环遍历学生集合,学生第n志愿为当前导师的Id则列入局部学生集合变量

    List<Student> tempStudentList = new ArrayList<Student>();for (Student student : Global.studentList) {int[] application = student.getSapplication();//学生第round个志愿与教师匹配if (application[round] == teacher.gettId()) {// System.out.println(student.getsName() + "----此轮志愿选择---"// + teacher.gettName());// 将此志愿的学生加到临时列表中tempStudentList.add(student);}}

3. 如果集合内的学生总数大于等于老师的可选择的学生人数上限,则根据集合内学生的排名,选择排名靠前的等于老师选择学生人数上限的学生,并把被选择的学生从全部学生的集合中删除,将导师的可选择学生人数上限置零,并把该导师从导师集合中删除

    // 按绩点从大到小排序Collections.sort(tempStudentList, new SortByGradePoint());// 获得该教师当前限选人数int sectionCurrent = teacher.getSectionRest();/*** 当前申请列表人数大于等于设置人数*/if (tempStudentList.size() >= sectionCurrent) {List<Student> myStudentList = new ArrayList<Student>();for (int i = 0; i < sectionCurrent; i++) {Student s = tempStudentList.get(i);myStudentList.add(s);// 将该学生列表添加到当前教师目录下teacher.addStudent(s);// 将该学生从总学生列表中移除Global.studentList.remove(s);Global.countStu++;checked++;}// 更新该老师剩余人数为0sectionCurrent = sectionCurrent - sectionCurrent;teacher.setSectionRest(sectionCurrent);// 将当前教师存入已完成分配的集合中Global.doneTeacherList.add(teacher);// 将该老师从总教师列表中删除teacherIterator.remove();}

4. 如果集合内的学生总数小于老师的可选择的学生人数上限,则把集合内的学生添加到老师已选择学生的集合里面,并把集合内的学生从全部学生的集合中删除,将导师的可选择学生人数上限更新

   else {/*** 当前申请人数小于限选人数*/sectionCurrent = sectionCurrent - tempStudentList.size();// 更新当前教师剩余人数teacher.setSectionRest(sectionCurrent);for (int i = 0; i < tempStudentList.size(); i++) {Student s = tempStudentList.get(i);// 将该学生添加到当前教师目录下teacher.addStudent(s);// 将该学生从全局学生列表中移除Global.studentList.remove(s);Global.countStu++;checked++;}
}
  • 共五轮,在匹配算法方法中加入参数round表示第几轮,另外建立class文件编写主函数实现算法的调用

      public void allocteStudent(int round) {

这是我们进行g和v数值测量得到的结果


输出和主函数

  • 在PrintUtils.java中定义方法输出总的学生和导师信息以及调用匹配算法后详细地结果


  • 在test.java中调用各种方法实现导师选择以及最终输出未被导师选择的学生人数(输出结果在附件中)

  • !!!!一次随机输入的输出结果


总结

软工第一次写代码很慌很慌,一开始是懵逼的,觉得很难的样子,但其实只要开始认真地思考问题,总能慢慢地解析题目,找到突破点,以及通过揣摩老师的要求慢慢地完善代码。代码完成实现输入输出的那一刻很开心。

一次作业任务下来,我们讨论了3次,花费了5个多小时,第一次讨论围绕了生成程序代码的编写和匹配算法的主要思想,这时候我们还没有导师热度值的想法,第二次是项目的建立以及git的使用,实现在coding.net上面提交代码和文件,第三次是对匹配算法的优化,我们提出了热度值的想法,一次一次的讨论,都是为了能在作业当中获得更高的分数,以及实现对自己的突破,并且博客的编写也经过了两个人多次的整合,努力完善博客的内容。

结对感受

  • 对于第一次结对编程,其中的感受是有好有坏的。好处在于两个人的力量无疑比一个人强大很多,并且不是简单的1+1,比如在生成程序和匹配算法思想的讨论当中,我先提出自己的想法,队友马上就能在我的想法上面衍生出更多的想法,并且能发现对方想法当中的缺点并且共同思考改进的方法,提高了工作的效率和减少代码编写当中犯错的次数。坏处在于代码的分工,两个人编写代码的习惯也不同,这就对代码整合造成困难,这是我们作为一个团队在合作当中需要磨合和学习的,所以在结对过程当中我们也认识到这个困难并克服。

  • 李佳恺:“黄家俊的编写代码的能力比我强很对,Java学的比我深入,比我熟悉,所以在结对当中他完成代码的部分较多,所以工作量占得也比较多,而且这是主动去做的,这一点我很不好意思也很感谢,所以我也尽最大努力地写好随笔,希望能为两个人获得更高的分数,并且我需要加紧Java的学习,毕竟后面还有团队的项目,加油!”

  • 黄家俊:“在此次结对编程中,感受最深的应该是团队交流吧。在整个过程中我和佳恺的交流基本上不存在障碍,我们都能从对方的表达中得到明确的信息,很容易将各自表达的观点扩展开来讨论。其中很关键的一点是,在编码过程中我遇到一个难题,自己一个人想了许久没找到根源,然后在和佳恺交流过程中,灵光一闪,找到了解决的方法。所以在这次合作中,愈发感觉到团队合作的重要性,希望之后还有合作的机会。”

我们的代码----Coding.net

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/250623.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

内置函数二

内置函数: 1.lambda 匿名函数 lambda 参数:返回值 例    resultlambda x,y:xy sresult(x3,y4) print(s) 2.sorted 排序 sorted(iterable, keyfunc, reverseTurn/False) 例    lst [1, 8, 18, 19, 97, 12, 3] lst.sort() lst自带的排序功能  l2 sorted(lst) 排序…

vue --- 2.0响应式补充

补充: 数组的响应式 // 对数组的方法进行重写 // 1. 不能影响本来的方法 // 2. 调用的时候可以找到它 let odlArrayPrototype Array.prototype; let proto Object.create(odlArrayPrototype); // 继承 [push,shift,unshift].forEach(method >{proto[method] function(){…

OptaPlanner - 把example运行起来(运行并浅析Cloud balancing)

经过上面篇长篇大论的理论之后&#xff0c;在开始讲解Optaplanner相关基本概念及用法之前&#xff0c;我们先把他们提供的示例运行起来&#xff0c;好先让大家看看它是如何工作的。OptaPlanner的优点不仅仅是提供详细丰富的文档 &#xff0c;还为各种应用场景提供丰富的示例&am…

es6 --- 使用proxy对数据进行劫持

说明: 数据劫持,简单的说就是在对数据进行操作(增删改查)时,触发的函数下面想通过使用以下的形式来使用: let proxy reactive({ name:lz }); proxy.name; // 获取 proxy.name 栗子; // 设置 delete proxy.name; // 删除解决方案: proxy函数的2个参数第一个参数: 接收一…

Java8-如何构建一个Stream

Stream的创建方式有很多种&#xff0c;除了最常见的集合创建&#xff0c;还有其他几种方式。 List转Stream List继承自Collection接口&#xff0c;而Collection提供了stream()方法。 List<Integer> list Lists.newArrayList(1, 2, 3); Stream<Integer> stream li…

软件产品案例分析

软件产品案例分析 第一部分&#xff1a; 评测&#xff1a; 上手体验&#xff1a; 说实话&#xff0c;在老师布置这个作业之前我确实不知道有K米这个APP&#xff0c;我想这是很少去KTV的原因吧。。。不过在接到这个作业后&#xff0c;我就去百度了普及了一下这个app的相关知识。…

java/android 做题中整理的碎片小贴士(12)

1、edittext中设置最长字数&#xff0c;可在xml中加入android:maxLength"10"&#xff0c;可在java代码中加入editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(20)}); 2、edittext监听软键盘delete按键&#xff1a; Et.setOnKeyListener(new Vi…

POJ2777(线段树裸题)

题目&#xff1a;http://poj.org/problem?id2777 别忘了各地的return&#xff1b; 有可能输入的L<R&#xff0c;手动swap&#xff1b; 似乎是多组输入&#xff1f; pushup和pushdown的位置。 &#xff08;原来pushup只有一行&#xff09; 要开四倍数组。是这种写法的原因吧…

vue --- 2.0 编译的实现

初识 假设html中有如下dom: <div id"app"><!-- 插值绑定 --><p>{{name}}</p><!-- 指令解析 --><p l-text"name"></p><p>{{age}}</p><p>{{doubleAge}}</p><!-- 双向绑定实现 -->…

个人作业收官——软件工程实践总结

一、回望与展望 1.1 对比现在和开学初博客开篇的课程目标和期待 当初的目标&#xff1a; 提升团队合作的能力能够学习到开发的一系列流程&#xff0c;以及如何写高质量的代码加强自己的编码能力&#xff0c;以及编码习惯熟悉不同平台的开发过程 如今&#xff1a; 基本的目标都…

sklearn中SVM调参说明

写在前面 之前只停留在理论上&#xff0c;没有实际沉下心去调参&#xff0c;实际去做了后&#xff0c;发现调参是个大工程&#xff08;玄学&#xff09;。于是这篇来总结一下sklearn中svm的参数说明以及调参经验。方便以后查询和回忆。 常用核函数 1.linear核函数: K(xi,xj)xTi…

TZOJ 3030 Courses(二分图匹配)

描述 Consider a group of N students and P courses. Each student visits zero, one or more than one courses. Your task is to determine whether it is possible to form a committee of exactly P students that satisfies simultaneously the conditions: every stude…

vue --- configureWebpack模拟后台数据

初识 使用vue/cli搭建的项目可以在vue.config.js中,模拟一个后台(express写法)vue.config.js configureWebpack: {devServer: {// 模拟后台服务器 express写法before(app) {app.get(/api/login, function(req, res) {const { username, passwd } req.query;console.log(user…

TCP和UDP的优缺点及区别

转自&#xff1a;http://www.cnblogs.com/xiaomayizoe/p/5258754.html TCP的优点&#xff1a; 可靠&#xff0c;稳定 TCP的可靠体现在TCP在传递数据之前&#xff0c;会有三次握手来建立连接&#xff0c;而且在数据传递时&#xff0c;有确认、窗口、重传、拥塞控制机制&#xff…

e.getMessage 为空NULL

e.getMessage 为空NULL 在日常代码中免不了要try catch 切忌用try catch 去try 整个方法。 在对象操作之前尽量写上if 空判断。 反例&#xff1a; public void send(){ try{ 代码1&#xff1a;获取对象 代码2&#xff1a;操作代码1 代码3&#xff1a;操作代码2 代码4&#xff1…

Linux:客户端的实现

写了一个简单的服务器软件&#xff0c;但是没有写客户端。现在我将客户端实现了&#xff0c;其实昨天已经说了客户端的实现步骤了。 步骤&#xff1a; socket() 初始化 connet()链接 从标准输入读数据fgets() 传数据到服务器write() 读从服务器返回的数据read() 写数据到屏幕上…

vue --- http拦截,登录登出的逻辑设计

设计 在src目录下创建一个interceptor.js登录逻辑 设置拦截,在发起请求前,先判断用户是否登录(在本栗中,即是否能够在浏览器缓存中找到token). 登出逻辑 对服务端传过来的数据进行拦截,判断其状态码是否为401(未登录或token过期)清空浏览器缓存中的token重定向到登入页面 inte…

循环分支循环语句

# 三大结构 - 循环 - 分支 - 循环 . . .In [ ]:# 分支 - 分支的基本语法 - if 条件表达式&#xff1a; 语句1 语句2 语句3 ..... - 条件表达式就是计算结果必须是布尔值的表达式 - 表达式后面的冒号觉对不能少 - 注意 if 后面出现的语句&#xff0c;如果属于 if 语句块&…

HTTP 1.1与HTTP 1.0的比较

HTTP 1.1与HTTP 1.0的比较 一个WEB站点每天可能要接收到上百万的用户请求&#xff0c;为了提高系统的效率&#xff0c;HTTP 1.0规定浏览器与服务器只保持短暂的连接&#xff0c;浏览器的每次请求都需要与服务器建立一个TCP连接&#xff0c;服务器完成请求处理后立即断开TCP连接…