第二次结对作业

队员

黄腾飞 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 = "/";    // 用于判断学生是否重复录入
...getset函数)
}

监测匹配是否存在

/*监测匹配是否存在*/
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   周静平  阅读(134)  评论(1编辑  收藏  举报

编辑推荐:
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
阅读排行:
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· DeepSeek火爆全网,官网宕机?本地部署一个随便玩「LLM探索」
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 上周热点回顾(1.20-1.26)
< 2025年1月 >
29 30 31 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31 1
2 3 4 5 6 7 8

导航

统计

点击右上角即可分享
微信分享提示