原创
学生考勤管理系统设计报告
2009-5-21 23:23
4285
6
6
分类:
软件与OS
1程序设计目的
通过设计、实现一个学生考勤管理系统,熟悉STL中有关类型及其使用方法,体会和掌握泛型编程的风格,加深对Visual C++集成开发环境的掌握(特别是调试功能),养成良好的编程习惯。
2系统设计要求
考勤信息记录了学生的缺课情况,它包括:缺课日期、第几节课(连续多节课用 begin-end 的形式表示)、课程名称(课程名称中不会出现空格)、学生姓名、缺课类型(迟到、早退、请假及旷课)。试设计一考勤管理系统,使之能提供以下功能:
1.录入学生的缺课记录:从键盘输入数据(提示:为避免重复从键盘输入数据,测试时可将数据存储在文件中,利用输入重定向功能读入),输入格式为:
缺课日期 第几节课课程名称 学生姓名缺课类型
每行一条纪录。
例如:
2008-04-29 3-4 C++程序设计实验张三 迟到
2008-04-28 3-4 C++程序设计李四 旷课
2.修改某个学生的缺课记录:可以对缺课纪录的任意部分进行修改,然后显示一下修改后的纪录。
3.查询某个学生的缺课情况:查询结果按照日期升序排序,同一天内按照所缺课程的时间升序排序。
4.统计某段时间内(以天为单位),旷课学生姓名及旷课节数,查询结果先按旷课节数降序排序,旷课节数相同的学生按姓名升序排序;
5.统计某段时间内,有学生旷课的课程及旷课人次,按旷课人次由多到少排序,旷课人次相同的课程按课程名称升序排序;
6.系统以菜单方式工作。(所谓菜单指用户可以自由选择所要执行的功能)
3系统功能模块图
4
4程序实现思路
4.1对数据结构的选择
由于这个系统涉及的查找较多,所以选择使用map,而且,还是多关键词的查找,对于其中用到的不同性质的关键词,可以分为——时间、学生姓名和课程名称。所以最后选择了三级map,以减少查询的时间。
第一级为第4个功能统计某段时间内(以天为单位),旷课学生姓名及旷课节数和第5个功能统计某段时间内,有学生旷课的课程及旷课人次都要用到的对时间索引。因为时间索引使用的选项最多,故选择时间为第一个key值。
第二级为第3个功能查询某个学生的缺课情况和第4个功能统计某段时间内(以天为单位),旷课学生姓名及旷课节数所要用到的对学生姓名的索引,故以学生姓名为第二个key值。
第三级为最后一个查找关键词课程名称。
4.2对功能的实现
4.2.1录入学生的缺课记录
考虑到多次录入学生的缺课记录,而再次学生的缺课记录有着不同的目的,或许是另一个教师使用,或者是追加最近信息等等。所以在实现时判断原记录是否为空,不空的话可以擦除原记录再写入,也可以在原记录的基础上追加信息。
而在添加信息时,有时候信息量较多,而且已经写成文档,或者是信息量不多,可以直接写入,所以既可以选择从文件读入,也可以选择从命令行直接读入。
4.2.2修改某个学生的缺课记录
在修改前当然要检查记录是否为空了,不为空的话,可以按以下三种方式进行查找该学生的缺课记录:
1、按时间索引;
2、按课程名字索引;
3、按学生名字索引
索引完成后,如果列出的选项太多而无法快速定位时,还可以选择进一步索引,当然索引方式还是上述三种。但两次索引的函数是不一样的,因为第一次笔者将map里的信息提取到vector以方便处理,进一步索引时是将vector里的一些信息剔除。随后仍然可以进一步索引,直到满意为止。
最后实现对所选记录的修改,完成后更新map记录。
4.2.3查询某个学生的缺课情况
这个模块只需要对map里的信息按学生姓名进行索引,然后对索引结果进行排序,最后将排序结果输出即可。而这个索引又是修改某个学生的缺课记录实现的一个子模块,所以只需要调用它,并对索引的vector排序即可。
4.2.4统计旷课学生姓名及旷课节数和有学生旷课的课程及旷课人次
这两个模块有较大联系,在此笔者将它们二者一起做对比描述。
统计旷课学生姓名及旷课节数和有学生旷课的课程及旷课人次之间既有联系又有区别。
联系在于:
1、都是统计某段时间内的情况
2、都是统计数量
区别在于:
1、一个是对学生姓名的统计,另一个是对于课程的统计
2、一个是统计旷课节数,另一个是统计旷课人次
所以针对两个模块不同之处使用函数变量来实现,这样就可以使用同一的函数接口。
4.2.5退出系统
在退出系统时,增加了将信息写入文件的功能,以便下次使用时直接从文本读入即可,增加了系统的易用性。
4.3索引功能的之间的联系
4.3.1初步索引函数之间的关系
初步索引函数分为三个方向:按时间初步检索、按课程名称初步检索和按学生名称初步检索,它们都要调用vector<Record> SearchInfo(Titer beg, Titer end, string className, string stuName );只是传入的参数有所不同而已。
4.3.2进一步检索函数之间的关系
和初步索引函数类似,进一步检索函数也分为同样的三个方向,但是它们不需要调用任何其他函数,只是在它们各自的内部针对不同的索引进行不同的筛选即可。
4.3.3按时间索引统计学生名称或课程名称函数之间的关系
按时间索引统计学生名称或课程名称的函数,有同一的函数进行解决void TimeIndexCount(const TimeStuCourseInfo& infoSearchRange, map<string, unsigned int> &m, string howToCount);只是最后一个参数传入不同的值,而它们又将调用void SearchInfo(Titer beg, Titer end, map<string, unsigned int> &m, CountFuntion CountWay),其中也是最后一个参数传入不同的值。
4.4索引功能的实现
4.4.1初步索引
按时间初步索引、按课程名字初步索引和按学生名字初步索引分别是
result = SearchInfo(TimeIndex, info);
result = SearchInfo(ClassNameIndex, info);
result = SearchInfo(StuNameIndex, info);
其中info为学生缺课信息,TimeIndex、ClassNameIndex和StuNameIndex分别是按时间初步索引、按课程名字初步索引和按学生名字初步索实现函数类型为vector<Record> FunctionFindInfo(const TimeStuCourseInfo &);
随后在vector<Record> SearchInfo(FunctionFindInfo, TimeStuCourseInfo)中,将调用上述FunctionFindInfo类型的函数,
在按三个初步索引函数中将分别指定时间的开始和结束值、课程名字或学生名字,然后调用vector<Record> SearchInfo(Titer beg, Titer end, std::string className, std::string stuName )函数,对时间先进行筛选,然后调用vector<Record> SearchInfo(Siter beg, Siter end, Record tmp, string className = string(), string stuName = string())对学生姓名进行筛选,最后调用vector<Record> SearchInfo(Citer beg, Citer end, Record tmp, string className = string(), string stuName = string()),对课程名字进行筛选。这个是由于选用三级map的结构决定的,在增加程序复杂性的同时,也降低了一些时间复杂度,使之接近于各索引的规模。
4.4.2进一步索引
按时间进一步索引、按课程名字进一步索引和按学生名字进一步索引分别是
result = SearchInfo(TimeIndex, result);
result = SearchInfo(ClassNameIndex, result);
result = SearchInfo(StuNameIndex, result);
虽然这些函数名和初步索引的一样,但各自的类型却不相同。
其中,SearchInfo函数的原型为vector<Record> SearchInfo(FunctionFindVector, std::vector<Record>);各进一步索引函数的类型为vector<Record> FunctionFindVector(const std::vector<Record>&);
各进一步索引函数索引函数内对传进的vector类型对各索引值进行进一步筛选即可得到最后结果。
4.4.3按时间索引统计学生名称或课程名称函数
这两个功能将分别调用CountPeriodStuName和CountPeriodClassName函数,这两个函数都将调用void TimeIndexCount(const TimeStuCourseInfo& infoSearchRange, map<std::string, unsigned int> &m, string howToCount);对于传入不同的howToCount的string值将分别调用void CountStuName(Siter beg, Siter end, map<string, unsigned int> &m)和void CountCourseName(Citer beg, Citer end, map<string, unsigned int> &m)。
其中void CountStuName(Siter beg, Siter end, map<string, unsigned int> &m)将对学生姓名进行扫描后,对于每个学生姓名对其每个课程进行累加。而void CountCourseName(Citer beg, Citer end, map<string, unsigned int> &m)只需对不同的课程统计学生旷课的人次即可,并不需要细究到不同姓名的学生。
文章评论(0条评论)
登录后参与讨论