2022秋软工实践 第二次结对编程作业
这个作业属于哪个课程 | fzusdn |
---|---|
这个作业要求在哪里 | 作业要求 |
这个作业的目标 | 生成指定条件数据集,实现效益最大的点名策略 |
学号 | 032004110 |
队友学号 | 032004119 |
commit记录
仓库(github)
一、背景分析
A.1、算法背景
栋哥对大家第一次结对编程作业的原型设计感到很满意,为了尽快让同学们使用上软件,于是栋哥花了一晚上时间开发了一个点名小程序。但是,在上线运行过后,发现了一些问题:
大多数老师习惯在每次上课后或下课前的一小段时间内进行点名。
如果采用全点的方式,在这段时间里,后端服务器需要处理大量的请求,拥塞导致响应速度变慢,给点名小程序带来极差的使用体验。
采用随机抽点的方式,能够有效减少并发量,但是无法保证点名的质量,难以有效抓出没有到教室的同学。
所以栋哥急需大家设计一个算法来解决这个问题,要求能够最小化后端发送的请求次数,最大化抓出缺勤同学的数量
A.2、具体要求
定义5门课程,每个课程班级人数为90人,一学期共20次课。每门课程均有5-8位同学缺席了该学期80%的课,此外每次课程均还有0-3位同学由于各种原因缺席。
B、实际背景
高校扩招,大学生逃课问题频发,理性逃课逐渐进入人们的视野。在功利主义风气的影响下,在逃课学生中,出现了一部分“逃课不逃学”的学生,他们基于对到课与逃课的理性分析,衡量逃课的成本和收益,在认为逃课成本小于收益时选择逃课(比如因兼职、做学生干部工作、考研、考证以及感觉逃课自主学习比到课听讲收获更大等逃课,而不因睡觉、玩耍、玩电脑游戏等逃课),我们称此为“理性逃课”。通过对文献的梳理及福建省3所高校的514份逃课样本及其中237份理性逃课样本进行分析发现:大学生逃课发生率很高;理性逃课占逃课近一半比例;理性逃课学生较一般逃课学生逃课次数少;逃课学生认为逃课对课程成绩影响很小;
根据调查研究目的编制了调查问卷,调查问卷分为两部分:第一部分是被调查学生的基本情况和对逃课的看法等;第二部分运用计划行为理论设计,采用李克特五分量表,分为行为态度、主观规范、感知行为控制和情境因素四部分。通过征询专家意见修改问卷后,进行小范围预调查,收到学生有效问卷28份,其中男生11份,女生17份,与被调查的福州大学、福建师范大学和福建农林大学等三所高校的学生性别比例大致相当。将28份问卷量表的数据输入SPSS 20.0中,对问卷量表进行信效度检验,通过计算,量表的Cronbach’s Alpha 值为0.882,十分接近0.9,各潜变量的信度值均超过0.7,表明量表具有较好的内部一致性。对量表进行效度检验得出,量表的KMO检验系数(Kaise-Meyer-Olkin Measure of Sampling Adequacy)为0.878,大于0.5;巴特利球形检验(Bartlett’s Test of Sphericity) χ2=3829.459,P
调查结果分析
1.逃课发生率很高
在758份有效问卷中,有逃课经历的共514份,即67.81%的大学生曾逃课,说明大学生逃课发生率很高,其现状不容乐观,值得引起重视。
2.理性逃课接近逃课比例一半
在514份有逃课经历的问卷中,根据理性逃课的定义,即问卷第11题“请问您逃课的原因是什么”,筛选出选择G选项“参与自习、做兼职、考证、学生干部工作等利于个人职业发展的事情”的学生问卷,对这些理性逃课学生的问卷样本进行更加深入分析发现,有逃课经历并选择G选项的样本共237份,逃课学生中46.11%是理性逃课,接近逃课比例一半,说明理性逃课学生比较多,也提示要正确理解、对待学生逃课,并对逃课分类治理。
3.理性逃课学生较一般逃课学生逃课次数少
福州大学、福建农林大学、福建师范大学学生一般逃课的比例分别为79.1%、63.0%、60.4%,表明三所高校的逃课现象不容乐观。值得关注的是,作为福建省重点建设的“211”高校――福州大学是三所高校中逃课率最高的,学生逃课率接近80%。福州大学、福建农林大学、福建师范大学学生理性逃课的比例分别为32.4%、31.1%、29.9%,福州大学的理性逃课率仍高于其他两所高校。也就是说,不同学校学生理性逃课严重程度不一,这与很多研究发现的学生逃课率因学校不同而不同结论相似,但和高校层次与学生逃课率成反比的结果存在出入。这既提示层次高的高校也应关注学校的教学管理和学风建设,又提示不同高校正确引导、针对性治理理性逃课的迫切性不同。
以上调查数据引用自qitong《大学生“逃课”的调查与分析》
因此,针对逃课的两种类型:理性逃课和惰性逃课,我们的算法中设计了不同的点名策略,以提高有效点名率。
二、算法模块说明
A、算法思路
我们通过Java实现数据集的生成和点名端策略算法,并通过Mysql展示每次的学生出勤情况和点名情况。
B、数据集生成
a、数据集特性(该校学生的上课习惯)
我们先按序产生学生的学号和姓名,之后按照正态分布,产生所有学生的绩点(2.0,0.5)。由于考虑到补考通过时,该学生绩点至少为1,因此,我们的绩点生成范围为1-4之间,不考虑绩点小于1的情况。又由于遵循了3σ原则,我们产生的绩点在1-4范围内的概率有0.9544,几乎可以看做是必然事件(但我们还是做了限制,对于产生范围之外的绩点,重新进行随机)。根据绩点,我们产生了出勤率(绩点/4),代表学生出勤该次课程的概率。虽然出勤率的起始值与绩点成正比,但由于后者会随着点名的进行而不断改变
,因此我们在此给出出勤率的变化规则:
- 学生分成坏学生与普通学生,坏学生无视点名策略出勤,普通学生则会根据不同的点名情况决定下次出勤情况。
- 若该学生此次课逃课,被点名点到,则下次出勤率大幅上升。
- 若该学生此次课出勤,被点名点到,若其为绩点稍好一些的学生,他会有求稳心理,他会觉得下次点名可能还是会被抽点到,所以其出勤率反而会小幅度的上升;但是,若该学生为绩点略差的学生(不包括坏学生),则他可能会产生一种侥幸心理,会觉得下次自己应该不会再次被点到,所以出勤率会小幅度下降。
- 若该学生逃课,且此次点名未被点到,则他可能会尝到甜头,觉得逃课也无关紧要,反正不会被点到,于是下次还会产生逃课的心理,其出勤率会大幅度的下降。
- 若该学生没逃课,且此次点名也未被点到,则不会对其内心产生影响,出勤率不会改变。
b、代码模块说明(由于代码太多了。。。。展现部分主要代码)
学生姓名生成
public static String insideFirstName(){Random random = new Random();int index = random.nextInt(firstName.length);return firstName[index];//获得一个随机的姓氏}public static int getNum(int start,int end) {return(int)(Math.random()*(end-start+1)+start);//获得一个随机的名字}public static int getNum(int start,int end) {return(int)(Math.random()*(end-start+1)+start);//产生名的个数1-2个}/*随机生成多个人名,通过list实现*/public ArrayList lineFistNameString(int index){ArrayList lineName = new ArrayList();BuildFirstName buildFirstName = new BuildFirstName();BuildLastName buildLastName = new BuildLastName();for(int i =0;i < 90;i++){lineName.add(buildFirstName.insideFirstName()+buildLastName.insideLastName(1));}return lineName;}
我们将生成数据集的过程又分为course、lesson、student三个模块(以下只展示course模块)
course(又臭又长)(只展示方法)
public class Course {private String name;private HashMap<Student, ArrayList<Integer>> records = new HashMap<>(); //记录学生出勤情况private ArrayList<Student> students = new ArrayList<Student>();//没点=0,点到逃跑的学生=1,点到没逃跑的学生=2private HashMap<Student, ArrayList<Integer>> pointRecords = new HashMap<>(); //记录点名情况private int courseNum;public int getCourseNum() {...}//得到课程数目---用于拓展public void setCourseNum(int courseNum) {...}//得到课程数目public void setStudents(ArrayList<Student> students) {...}//设置该课程所有学生public ArrayList<Student> getStudents() {...}//得到该课程所有学生public void addStudent(Student student) {...}//添加学生public void addStudents(ArrayList<Student> students) {...}//添加学生集(所有学生)public HashMap<Student, ArrayList<Integer>> getRecords() {... }//得到该课程所有学生出勤率public void setRecords(HashMap<Student, ArrayList<Integer>> records) {...}//设置该课程所有学生出勤率public void putRecord(Student student, Integer integer) {...}//添加单个学生出勤率public void putRecords(Student student, ArrayList<Integer> arrayList) {...}//添加所有学生出勤率public HashMap<Student, ArrayList<Integer>> getPointRecords() {...}//得到点名端出勤率public void setPointRecords(HashMap<Student, ArrayList<Integer>> pointRecords) {...}//设置点名端出勤率public HashMap<Student,ArrayList<Integer>> putPointRecord(Student student, Integer integer) {...}//添加点名端出勤率public void initStudentGrade() {...}//初始化该课程所有学生绩点(正态分布)public void initStudentMis() {...}//初始化该课程所有学生出勤率(初始)public String getName() {...}//得到该课程名字public void setName(String name) {... }//设置该课程名字public void selectBadStudents() {...}//挑选出坏学生public void recordMis() {...}//生成一次课程缺勤名单,记录在records里public boolean isBad(int index) {...}//判断该学生是否为坏学生public boolean haveStudent(Student student_) {...}//判断该课程中是否有这个学生public Student dropBad(Student student){...}//点名策略方法,根据上一次,若点到逃跑,就接着点他(有释放机制)public Course pointBadStudent(Course course, int cnt) {...}//点名端点坏学生机制public Course pointAllBadStudents(Course course, int cnt) {...}//点名端点所有坏学生机制public Boolean isGoodPoint(Student student, int cnt) {...}//点名端判断是否为普通学生public Student findPointStudent(Student student){...}//在点名端寻找该学生public Course pointGoodStudent(Course course, int cnt) {...}//点名端点普通学生机制public int findStudent(String No) {...}//通过学号寻找该学生public ArrayList<Integer> selectBadIndex() {...}//找出坏学生的学号public Student initbadRecords(Student student){...}//初始化坏学生出勤课程public String infoPointRecords(Student student, int cnt) {...}//初始化点名端所有学生出勤记录
}
三、点名策略
首先,我们点名方只有点到的同学,才知道其出勤情况,而对于未被点到的学生,即使其逃课,但点名端依旧不知道,所以相关点名算法无法计算到。
对于坏学生:我们采取首次课全点后20位同学,若后20位同学中有人逃课,则先视其为坏学生,对于坏学生,我们选择每次都点的策略。坏学生释放机制:若累积5次及以上的课程没逃课(我们点到其姓名,但是他出勤了),我们就将其释放,将其重新当做普通学生。
对于普通学生:我们按照绩点生成初始的出勤率,然后根据视出勤率的概率等同于点其名字的概率作为我们算法的基本策略,但是由于我们对学生的出勤率设置了调整机制,故对于点名端已点到的普通学生,也会根据其出勤情况,动态更新点名端的学生出勤率(注意:若其未被点到,则不知道其出勤率变化)。
关于出勤率与是否点名的关系(通过举例说明):若出勤率为60%,点名率也为60%的情况下,虽然值相同,但是由于这仅仅只是概率,还是会存在有很多学生选择逃课,并且点名端选择点名的。
四、算法创新性
- 设置了学生出勤率的变化机制,即:根据点名的不同情况,对学生的出勤率进行调整。
public void missRateUp() {setMis_rate(getMis_rate() - getMis_rate() / 4 * Math.random());//降低学生的出勤率
}
public void missRateDown() {setMis_rate(getMis_rate() + getMis_rate() / 4 * Math.random());//提高学生的出勤率
}
- 通过对数据库进行读写操作,写入每门课程所有学生的出勤情况(1代表出勤),并在点名端读出(0代表未被点到,1代表被点到且其逃课,2代表被点到但没逃课)。
学生出勤情况:
点名端点名情况:
- 算法具有学习率,即点名过程也是点名算法不断完善的过程。
- 算法是采用了面对对象,即:该算法不是面向结果,更符合实际情况。
- 算法具有可拓展性,即:不仅仅限制于题目所给的数据,可人为改变人数课程数等要求。
- 算法具有稳定性,经过持续不断的学习,在20次时该算法有效点名率能稳定在80%。
五、结果可视化(优秀的学习率嘿嘿)
六、结对过程
本次结对作业,由于我们选择了Java进行算法的设计与实现,每个人又有自己不同的编写框架,于是,在写算法的过程之中,我们采取了一人先对基本算法框架进行构建,之后再分功能模块对算法进行具体完善和填充。
七、心路历程
此次软工作业,我们经历了大致三个阶段;第一个阶段,我们先花了一些时间构思算法大概的实现方法,讨论了数据集生成的方式、点名端的实现方式以及如何满足题目的条件。第二个阶段是算法编写阶段,在此过程中,我们在编写的时候也不断的在讨论和完善我们的算法,由于对于一些问题存在不同的看法,也想了很多的解决方案。第三个阶段是debug处理阶段(这个阶段是真的真的真的非常折磨,,,,),由于代码很多,在处理这些debug的时候一个处理完又出现一个,而且由于各模块之间是互通的,在处理这部分debug的时候非常繁杂,不仅仅是这个模块要改,其他模块可能也跟着一起要改0.0,由于我们对Java传参的理解有些偏差,在改debug这块真的花了好多时间(两天快肝了24个小时0.0)。
PSP
PSP | 预估耗时/分钟 | 实际耗时/分钟 |
---|---|---|
题目分析 | 20 | 30 |
思路讨论 | 60 | 80 |
算法编写 | 1800 | 1950 |
模块化处理 | 100 | 120 |
debug处理 | 600 | 1800 |
结果测试 | 30 | 20 |
代码规范 | 20 | 30 |
拓展性测试 | 40 | 60 |
博客编写 | 200 | 300 |
合计 | 2870 | 4390 |
学习进度表
第N周 | 新增代码(行) | 累计代码(行) | 本周耗时(h) | 累计学习耗时(h) |
---|---|---|---|---|
1 | 600 | 600 | 1 | 1 |
2 | 758 | 1358 | 1 | 2 |
结对照片
八、重难点及思考
本次问题的难点在于:我们选用Java进行实现,那么就要非常注意Java的传参过程和面向对象的过程。我们花了很多的时间在该问题数据集的产生上;如何才能产生既满足题目要求的数据集,又比较贴合实际的数据集呢?同时,由于我们是面向对象的过程,该算法虽然有很强的学习力,但是,学生端和点名端之间有很强的交互性,这就导致在编写算法的时候,要十分小心我们修改的对象是否是该模块的对象。再者,由于考虑到实际情况下并不会是给定的人数和课程数,因此,我们还需要考虑的是算法的拓展性。最后,在debug这块,我们也学会不能对一种语言的基本用法产生偏差,否则后果很严重…
九、感想
结对作业难就难在每个人都可能会有自己的想法,意见产生偏差是很正常的现象。在意见分歧时,如何通过沟通解决问题是我觉得是这次结对作业中最重要的一环。同时,代码编写完成之后,在复查的过程中,可能两人对算法实现的功能的理解有所不同,所以,可能就会导致最终的结果并不是我们所希望得到的。由于我们设计算法的思路是:一个人先将大致模块构建好,接着再进行不同模块的分配。因此,在算法对接的时候,就很需要两个人进行沟通。同时,在代码编写完成之后,debug的解决过程也体现了结对合作的优势。这种优势不仅仅是能够多一个人多一分力,并且在精神上也很好的给予了对方鼓励,形成一加一大于二的效果。
(插一嘴 子键哥好猛hahaha)
—DongY
本次结对作业,收获还真的是意外的大。首先是单纯的代码层面,java只能值拷贝(值传递),着实让我吃了一壶,而本次作业我用java实现,由于写着写着写的多了那么亿点点(我真的是想法只多了一点点。。没想到实现起来会多辣么亿点点。。),导致我写着写着忘记了java值传递的特性,埋下了亿点点的bug,所以导致写代码以及理清代码结构本就耗费了比较多的时间,然后随后运行时抛出的n多的null值hah,让我和我的队友在debug阶段花了整整两天时间,基本就是从早改到晚,然后第二天起来继续debug,还真是“痛苦”,也着实影响深刻了。然后是合作方面,一开始我们尝试着双方一起写不同功能的代码,但由于双方使用java的代码规范没有确定,在对接代码的方面,反而会耗费很多时间,甚至其中一方写的代码,要另外一方重新改过才行,所以我们就决定由我先写好一些代码架构,抽象好接口,注释上写好应要完成的功能,然后双方再进行代码实现,这样大大的减少了对接的时间开销,然而,也是因为这个缘故,最终导致了上面说的辣么多bug(都是我的错),在最后的debug阶段,我们共同检查代码功能与逻辑,我们坐在电脑面前debug,发现bug后由我来改写代码,另外一方检查我新写的代码逻辑是否有问题(感觉一开始就这么搞可能会好点。。。),来确保新写的代码不会有bug,然后即便如此,我们还是陷在1k多行代码debug了整整两天,真的体验到了程序员的痛苦hah,一边debug,一边还要担心ddl的来临,太折磨辣,但患难之后,毫无疑问,我和我的队友产生了更强的革命感情hah,而改完全部代码的那一刻,真的是hah 爽嗷!
—zijian
2022秋软工实践 第二次结对编程作业相关推荐
- 2022秋软工实践2:结对编程
这个作业属于哪个课程 https://bbs.csdn.net/forums/ssynkqtd 这个作业要求在哪里 https://bbs.csdn.net/topics/608739561 这个作业 ...
- 2022秋软工实践 第一次结对编程作业
2022秋软工实践 第一次结对编程作业 需求分析 (1)Need,需求 (2)Approach,做法 (3)Benfit,好处 (4)Competitors,竞争 (5)Delivery,推广 UML ...
- 2022秋软工实践个人作业二
2022秋软工实践个人作业二 Task I Task II 这个作业属于哪个课程 软工实践 这个作业要求在哪里 2022秋软工实践个人作业二 这个作业的目标 git html 学号 032002342 ...
- 软工实践第二次结对作业
1.结对成员: 031502340 易伟航 031502312 黄阳正 2.项目的Github链接: 第二次结对作业 3.数据和"数据生成"程序的原理以及我们所考虑的因素: 生成数 ...
- 2022秋软工实践 栋感光波团队需求分析文档
需求文档 文章目录 需求文档 1 引言 1.0 1.1编写目的 1.2背景 1.3迭代记录表格 2 任务概述 2.1 项目概述 2.1.1 项目来源及背景 2.1.2 项目目标 2.1.3 系统功能概 ...
- 软工实践第二次结对作业(作业五)
结对同学的博客链接 本作业博客的链接 Github项目地址 分工明细 李麒:负责词频统计的设计.编码,类图的构建.性能分析和单元测试,博客代码部分的撰写. 陈德斌:负责爬虫工具学习.使用,博客的爬虫等 ...
- 【软件工程】2022秋软工实践个人作业一
自我介绍 | 这个作业属于哪个课程 | https://bbs.csdn.net/forums/ssynkqtd | | ----------------- |--------------- | | ...
- 软工实践 - 第二十二次作业 项目测评(团队)
测评项目 : 福大助手 组长博客链接:https://www.cnblogs.com/dawnduck/p/10093752.html 第一部分:调研,评测 评测 1. 第一次上手体验 安卓: 进入页 ...
- 2021秋软工实践第一次结对编程作业
这个作业属于哪个课程 构建之法-2021秋-福州大学软件工程 这个作业要求在哪里 2021秋软工实践第一次结对编程作业 这个作业的目标 实现博饼软件原型并进行博客写作 学号 031902139 队友学 ...
最新文章
- 关于 AppDelegate 、UIApplication 简单的用法
- centos7 yum下载路径
- post php数据,php post数据
- 【转载】C/C++语言分析 每年学一种编程语言 git历史
- 【并查集】银河英雄传说 (luogu 1196/ssl 1225)
- 关于队列(数组队列,链表队列,循环队列)
- SSL、OPENSSL、SSH、OPENSSH
- QQ域名拦截检测工具(含源码)
- shell的EOF用法
- C 什么是句柄?为什么会有句柄?HANDLE
- Java中常见的异常举例
- JAVA查询银行卡信息
- mysql 怎么同时删除两张表的数据库,mysql怎样删除多个表格数据库数据_数据库
- Win11怎么打开AMD显卡控制面板
- Python 的七大就业方向,总有一个适合你!
- Android 给RecyclerView添加头部和尾部
- 久别重逢,畅快开吃!
- 前端向--BLOB文件处理及常用输入校验
- 从游戏开发到web前端——仅仅只是开始
- 中国全轮驱动系统行业市场供需与战略研究报告