• 软件工程结对项目第二次作业


    软件工程结对项目第二次作业


    031502210 邓弘立
    031502245 郑荣尧

    项目Github:

    https://github.com/Maple27/S-D_Match

    最“好”的数据

    https://github.com/Maple27/S-D_Match/blob/master/input_data.txt

    生成原理:
    • 根据所给的的Json数据格式,构造出输入格式的bean类。对于数据的生成,采用了Java随机数生成的方法,将部门和学生的数据生成。生成数据时,我考虑了可能的重复性,所以在生成后对冗余(重复)数据进行了筛选和删除,保证了数据的完全随机性。

    数据建模

    • 主函数类:生成数据类对象,执行输入输出,生成结果,程序的入口。
    • 学生类:拥有学号,空余时间,兴趣TAGS,意愿,是否被部门选中和对各部门的优先级的成员属性,并拥有对应的Getter和Setter方法
    • 部门类:拥有部门ID,活动时间表,部门类型TAGS和上限人数的成员属性,并拥有对应的Getter和Setter方法
    • 输入Bean类与输出Bean类:通过InputBean类将从txt文件读取的Json转换为程序中的数据以使用。通过OutputBean类将程序运行得到的结果转换成Json数据并输出到txt文件中。
    • 匹配类:核心类,承载数据的初始化和输入输出的方法,同时具备对部门学生进行排序和智能匹配的核心算法。
    • 数据生成类:自动生成数据的类,主要通过随机数实现。

    匹配程序思路

    • 要做到部门和学生匹配,首先要明确的目标应该是部门所能接纳的人数和学生总数的关系。
      在部门能接纳的人数大于学生人数的时候,学生应该具有优势选择权,最优方法是遍历学生匹配部门;
      当学生人数超过部门接纳人数时,部门占据优势,最优方法应该是遍历部门逐个匹配学生;
      本题学生300人,部门20个,各部门人数10-15,满足后者条件。所以采用了DtoS的匹配方式。
      本人采用了优先级算法,以意愿为基本条件,兴趣和时间为辅助条件对学生进行进行排序,优先级高的先被选中。

    实现方式

    • 读入当前目录下input_data.txt文件
    • 根据读入的文件通过bean类解析并初始化数据(学生,部门的信息)
    • 将部门根据tags的数量进行排序(使用了快速排序算法),tags少的部门优先进行匹配
    • 统计学生在各个部门的优先级,优先级算法如下:优先级初始为0.学生一周中每有1小时free_time与部门event_schedule时间对应,优先级+1,学生每有一个兴趣tag与部门tags对应,优先级+2.
    • 匹配过程:以学生志愿为基本条件(不符合即不选),从tags最少的部门开始,先对学生以在该部门的优先级进行排序,再按第一志愿到最低志愿,遍历学生(三重循环:部门-志愿-学生),符合即选中,并将结果加载到bean类。
    • 通过bean类构造json数据,输出output_data.txt

    代码规范

    • 主要以本人的代码习惯为主,搭档提供模型设计

    关键代码

        //根据部门tags数量从小到大将部门排序
    	public void sortDepartment(List<Department> list, int low, int hight) {
            int i, j;
            Department index;
            if (low > hight) {
                return;
            }
            i = low;
            j = hight;
            index = list.get(i);
            while (i < j) {
                while (i < j && list.get(j).getTagsSize() >= index.getTagsSize())
                    j--;
                if (i < j){
                	list.set(i++, list.get(j));
                }
                	
                while (i < j && list.get(i).getTagsSize() < index.getTagsSize())
                    i++;
                if (i < j)
                    list.set(j--, list.get(i));
            }
            list.set(i, index);
            sortDepartment(list, low, i - 1);
            sortDepartment(list, i + 1, hight);
        }
    
        //统计各个学生在各部门的优先级
    	public void countStudentScore(){
    		for(int i=0;i<departments.size();i++){
    			for(int j=0;j<students.size();j++){
    				List<String> dTimes = departments.get(i).getActivityTime();
    				List<String> sTimes = students.get(j).getFreeTime();
    				List<String> dTags = departments.get(i).getTags();
    				List<String> sTags = students.get(j).getInterests();
    				int score = 0;
    				//时间优先级统计
    				for(int m=0;m<dTimes.size();m++){
    					String str1 = dTimes.get(m);
    					String[] string2 = str1.split("\.");
    					String[] string3 = string2[1].split("~");
    					String[] string4 = string3[0].split(":");
    					String[] string5 = string3[1].split(":");
    					String day1 = string2[0];
    					int start1 = Integer.parseInt(string4[0]);
    					int end1 = Integer.parseInt(string5[0]);
    					for(int n=0;n<sTimes.size();n++){
    						String str2 = sTimes.get(n);
    						String[] string6 = str2.split("\.");
    						String[] string7 = string6[1].split("~");
    						String[] string8 = string7[0].split(":");
    						String[] string9 = string7[1].split(":");
    						String day2 = string6[0];
    						int start2 = Integer.parseInt(string8[0]);
    						int end2 = Integer.parseInt(string9[0]);
    						
    						if(day1.equals(day2)){
    							if(end1<=start2||end2<start1){
    								score += 0;
    							}
    							else if(start1<start2&&end1>start2&&end1<end2){
    								score += end1-start2;
    							}
    							else if(start2<start1&&end2>start1&&end2<end1){
    								score += end2-start1;
    							}
    							else if(start1>start2&&end1<end2){
    								score += end1-start1;
    							}
    							else if(start2>start1&&end2<end1){
    								score += end2-start2;
    							}
    						}
    					}
    				}
    				//兴趣优先级统计
    				for(int p=0;p<dTags.size();p++){
    					String tag1 = dTags.get(p);
    					for(int q=0;q<sTags.size();q++){
    						String tag2 = sTags.get(q);
    						if(tag1.equals(tag2)){
    							score += 2;
    						}
    					}
    				}
    				//将此部门与学生匹配的优先级加入学生信息中
    				students.get(j).getScores().add(score);
    			}
    		}
    	}
    	
    	
    
        //部门-学生匹配算法(D->S)
    	public void match_DtoS(){
    		for(int i=0;i<departments.size();i++){//部门遍历
    			int num = 0,flag = 0;
    			//每次对一个部门招募时以学生对此部门的分数对学生进行重新排列
    			sortStudent(students, 0, students.size()-1, i);
    			for(int j=0;j<5;j++){//志愿遍历
    				for(int k=0;k<students.size();k++){//学生遍历
    					//超限 下一个
    					if(num>=departments.get(i).getLimit()){
    						flag=1;
    						break;
    					}
    					//志愿不足 下一个
    					if(students.get(k).getWillsSize()<=j) continue;
    					String wills = students.get(k).getWills().get(j);
    					String no = departments.get(i).getId();
    					if(wills.equals(no)){
    						//符合志愿条件,根据符合分数进行分配
    						departments.get(i).getMembers().add(students.get(k));
    						students.get(k).setFlag(1);
    						num++;
    					}
    				}
    				if(flag==1) break;
    			}
    			departments.get(i).setNum(num);
    		}
    		for(int i=0;i<departments.size();i++){
    			for(int p=0;p<departments.get(i).getMembers().size()-1;p++){
    			    for(int j=departments.get(i).getMembers().size()-1;j>p;j--){
    			      if(departments.get(i).getMembers().get(j).equals(departments.get(i).getMembers().get(p))){
    			    	  departments.get(i).getMembers().remove(j);
    			      } 
    			    } 
    			}
    	
    		} 
    	}
    

    结果评估

    • 对于匹配结果,由于部门能收纳的人数小于学生总数,但却没有达到部门人数为满,可能是数据限制,但大概率是匹配算法的不足。这个匹配算法是自己想出来的,对数据进行了较多的前期处理,但在核心的匹配层面上可能还有很大的缺陷,一时间不知道如何改进。但结果的匹配率本人还是满意的,符合大学生部门招收新人的大致思路,基本没有遗漏最好的人选(兴趣时间双重占比考虑)。

    • 助教的测试样例中可以跑出62个未被选中的学生和248个被接收的学生总数以及0个没有被选中的部门。自己生成的输入数据中未被选中的学生大致在60-80之间,被接收的学生总数在240-270之间,且未发现有没被选中的部门。

    结对感言

    • 这次结对赶上国庆中秋双节假期,和搭档没有上一次那么多的交流,但通过QQ还是确立了基本的思路,并且在算法上进行了深入的讨论,对这次程序的产生还是十分满意的,希望下次能越做越熟练。
      搭档这次在数据建模和设计图方面贡献较大,希望他能提高代码能力,望互相补足。
  • 相关阅读:
    快速挂载和分离VHD文件的小脚本
    开机自动挂载 VHD 的方法
    搭建属于你自己的RAMOS系统 – WIN7+VHD+GURB map方式
    去除右键的opendgl
    为XYplorer添加右键菜单:“使用XYplorer打开”
    用VB把xls转换为xlsx
    用VB把xlsx转换为xls
    把Excel工作簿的每个工作表提取出来保存为新工作簿
    (转载)uefi启动解析:由原理到实例
    理想中的SQL语句条件拼接方式 (二)
  • 原文地址:https://www.cnblogs.com/Maple27/p/7642722.html
Copyright © 2020-2023  润新知