第二次结对作业

队员

黄腾飞 170327033
周静平 170327112

作业需求分析

  • 使用文件录入20个部门,300个学生
  • 部门含有以下属性:
    1、 名称:单个字符串
    2、 编号:单个字符串
    3、 学生人数上限:单个数值
    4、 特点标签:多个字符串
    5、 多个常规活动时间段
  • 学生含有以下属性
    1、 姓名:单个字符串
    2、 学号:单个字符串
    3、 绩点:单个数值
    4、 意愿部门:小于等于5个的多个字符串
    5、 空闲时间段:多个字符串
  • 进行智能匹配,智能匹配要求如下:
    1、 代码规范
    2、 为输入输出设计标准化、通用化、可扩展的接口
    3、 使用不同优先级匹配
  • 文件输出匹配结果,结果种类如下:
    1、 已匹配结果
    2、 未匹配部门
    3、 未匹配学生
  • 生成可执行的exe文件
  • 结果分析
  • 提交代码到Github
  • 撰写博客

设计思路

  • 配置文件定义输入输出文件以及优先级(可定义多个优先级)
  • 编写生成输入文件的代码,模拟输入信息
  • 获取部门和学生信息
  • 按照志愿顺序进行匹配
    1、 遍历所有学生(从i到n)
    2、 遍历所有部门(从j到m)
    3、 先按照i学生一志愿进行匹配
    4、 i学生的志愿部门如果已存在匹配列表则加入匹配列表,否则建立一个部门对应多个学生的匹配列表
    5、 一志愿匹配完毕后判断学生数是否达到上限,如果达到则进入下一个学生,否则,继续进入下一个志愿的匹配
    6、 如果配置中存在一个或者多个优先级,遍历每个优先级,如果没有则进入第10步
    7、 如果存在绩点优先则将匹配列表中的学生按照绩点排序,选取绩点前j部门学生人数上限的k个同学,如果k>j,匹配队列进入后续处理(第10步),否则标记学生为已匹配
    8、 如果存在兴趣优先则按照学生兴趣与j部门的特点相同的个进行排序,类似绩点选取学生进行操作
    9、 如果存在空闲时间优先,则类似兴趣优先进行操作
    10、 将匹配数大于上限的匹配列表进行随机筛选部门上限个数的学生
  • 打印匹配信息
  • 优化接口

代码关键部分

部门类

public class Department {
private String departmentName;  // 名称
private String departmentCode;  // 编号
private Integer studentLimit;   // 限制学生数[0-15]
private ArrayList<String> characteristics = new ArrayList<>();  // 特点标签
private ArrayList<String> routineActivityTime = new ArrayList<>();  // 常规活动时间
private boolean ismatch = false;    //  是否匹配标识
...
(get和set函数)
}

学生类

public class Student {
private String studentName = null;  // 姓名
private String studentCode = null;  // 学号
private Float gradePoint = null;    // 绩点
private ArrayList<String> interest = new ArrayList<>(); // 兴趣爱好
private ArrayList<String> departmentWishes = new ArrayList<>(); // 意愿部门
private ArrayList<String> freeTime = new ArrayList<>(); // 空闲时间
private boolean isMatch = false;    // 是否已被匹配
private int sameInterestsNum = 0;    // 爱好相同数
private int sametime = 0;   // 空闲时间匹配数
private boolean ismatch = false;    // 是否匹配标识
...
(get和set函数)
}

部门与学生的匹配类

/*记录一个部门匹配多个学生信息*/
public class D_S_Match {
private Department department;  // 部门
private ArrayList<Student> students = new ArrayList<>();    //多个学生
private String studentStr = "/";    // 用于判断学生是否重复录入
...
(get和set函数)
}

监测匹配是否存在

/*监测匹配是否存在*/
try{
    d_s_matches.get(j);
}catch (IndexOutOfBoundsException ioobe){
    /*不存在则建立一个匹配*/
    D_S_Match dsm = new D_S_Match();
    departments.get(j).setIsmatch(true);
    dsm.setDepartment(departments.get(j));
    d_s_matches.add(dsm);
    if (!d_s_matchesStr.matches("/"+departments.get(j).getDepartmentCode()+"/")){
        d_s_matchesStr = d_s_matchesStr + departments.get(j).getDepartmentCode() + "/";
    }
}

意愿匹配部门

//  志愿级别改变,判断人数是否够了
if(isChange && d_s_matches.get(j).getStudents().size()>=d_s_matches.get(j).getDepartment().getStudentLimit())break;
isChange = false;
/*意愿部门匹配部门*/
String[] dw = students.get(i).getDepartmentWishes().get(index).split("/");
if ((dw.length==1 && dw[0].equals(departments.get(j).getDepartmentName())) || (dw.length==2 && dw[0].equals(departments.get(j).getDepartmentCode()))){
    if (!d_s_matches.get(j).getStudentStr().matches("/"+students.get(i).getStudentCode()+"/")){
        d_s_matches.get(j).addStudents(students.get(i));
        break;
    }
}

使用内置快速排序算法

/*按绩点降序排序*/
private void sortByGradePoint(ArrayList<D_S_Match> d_s_matchesCopy){
    for (int i = 0;i<d_s_matchesCopy.size();i++){
        Collections.sort(d_s_matchesCopy.get(i).getStudents(), new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                return s2.getGradePoint().compareTo(s1.getGradePoint());
            }
        });
    }
}

匹配类使用多构造函数

public DepartmentOfStudentMatchingImpl(){}
/*参数是否初始化*/
public DepartmentOfStudentMatchingImpl(Boolean goInit){
    if (goInit) init();
}

匹配类初始化

/*初始化数据-获得部门和学生信息*/
public void init(){
    if (config==null) config = new Config(true);
    MatchIO matchIO = new MatchIO(config,true);
    if (departments==null) departments = matchIO.getDepartments();
    if (students==null) students = matchIO.getStudents();
}

接口

public interface DepartmentOfStudentMatching {
    void init();    // 初始化-获得学生和部门
    void matching();    // 进行匹配运算
    void print();   // 打印匹配结果
    <T> void othersPriority(T priority);    //  其他匹配方式,使用泛型参数
    void setConfig(Config config);  // 设置配置文件
    Config getConfig(); // 获得配置文件
    ArrayList<Department> getDepartments(); // 获得部门信息
    void setDepartments(ArrayList<Department> departments); // 设置部门信息
    ArrayList<Student> getStudents();   // 获得学生信息
    void setStudents(ArrayList<Student> students);  // 设置学生信息
}

数据

配置文件数据


importfile[空格][输入文件地址]
outputfile[空格][输出文件地址]
priority(空格)(优先级)(空格)(优先级)(空格)(优先级)

生成的输入数据

生成的输出数据

算法测试报告

优先条件 匹配学生个数 未匹配学生个数 实际耗时(ms) 输出文件路径
绩点/兴趣/空闲时间 248 52 47 E:\web-app\project\第二次结队作业\IntelligentMatch\src\config\output.txt
兴趣/空闲时间 253 47 22 E:\web-app\project\第二次结队作业\IntelligentMatch\src\config\output(1).txt
绩点 218 92 28 E:\web-app\project\第二次结队作业\IntelligentMatch\src\config\output(2).txt
绩点/兴趣 240 60 25 E:\web-app\project\第二次结队作业\IntelligentMatch\src\config\output(3).txt
其中耗时只计算匹配时的耗时

程序优势

  • 默认使用配置文件来设置输入输出文件以及优先级,有极大的灵活性
  • 默认输入文件格式简单,方便输入
  • 程序可以不使用文件而使用其他方式录入学生和部门信息,保留录入信息的接口
  • 程序可以不使用文件而使用其他方式来录入配置信息
  • 除了默认的4种匹配方式以外,还可以进行重写othersPriority(T priority)来增加匹配方式

总结感受

这次的作业相对于上次有较大的难度,上次只是进行原形的设计,需要的是大胆的想想能力和创造能力,这次主要需要的是代码能力和自身的基础积累。这次的作业,在两个人的沟通上,没有上次那么简单,除了基本逻辑之外,在代码上,对于自身写的代码,如果注释不够清晰明了,很难让对方读懂;同时对方的代码注释清晰明了,我也得花段时间捋一捋才能明白。不过还好的是,这些东西在实验室的项目上遇到过,也学了不少东西,在这里不是很大的坎。

GitHub地址

posted on 2017-10-25 00:18  依呼呼  阅读(146)  评论(1)    收藏  举报

导航