数据结构实训——成绩统计系统
1 课题描述
给出n个学生的m门考试的成绩表,每个学生的信息由学号、姓名以及各科成绩组成。对学生的考试成绩进行有关统计,并打印统计表。
2 问题分析和任务定义
(1) 按总分数高低次序,打印出名次表,分数相同的为同一名次;
(2) 按名次打印出每个学生的学号、姓名、总分以及各科成绩。
(3) 注意测试边界数据。
(4) 对各科成绩设置不同的权值。(附加功能)
3 逻辑设计
1)数据类型:
对于学生所包含的信息,学号使用整数型,姓名使用字符串型,各科成绩和总成绩还有加权成绩使用浮点型。同时设置浮点型数组来存储各科所占权值的比率,设置整数型数组来存储每个学生的排名。
struct STU
{
int id;///学号
char name[20];///姓名
float score[20];///成绩
float rsum;///加权后的总分
float sum;///不加权的总分
}s[110];
float ratios[30];///权值比率
int rerank[100];///学生排名
2)抽象数据类型
ADT Stu{
数据对象D:D是具有相同特征的数据元素的集合。各数据元素均含有类型相同,可唯一标识数据元素的关键字。
数据关系R:数据元素同属一个集合。
input(int n,int m)
操作结果:输入n个学生的学号,姓名,m科成绩。
quick_sort(int n)
操作结果:对n个学生按加权总分进行快速排序。
ranks(int n,int rerank[])
操作结果:对n个学生进行排名,加权总分相同的,获得相同的名次。
display(int n,int m,int rerank[])
按照排名打印n个学生的学号、姓名、总分和各科分数。
}ADT Stu
3)模块功能:
功能上分为输入、排序、排名、打印这三大模块。其中排序模块中需要使用排序算法给学生按照加权成绩排名。排名模块需要编写算法实现相同分数排名相同的要求。
4 详细设计
学生信息结构体:
struct STU
{
int id;///学号
char name[20];///姓名
float score[20];///成绩
float rsum;///加权后的总分
float sum;///不加权的总分
}s[110];
<1>输入函数: void input(int n,int m)
输入n个学生的学号,姓名,m科成绩。
<2>快速排序函数:void quick_sort(int n)
对n个学生按加权总分进行快速排序。
<3>相同名次处理:void ranks(int n,int rerank[])
对n个学生进行排名,加权总分相同的,获得相同的名次。
<4>打印函数void display(int n,int m,int rerank[])
按照排名打印n个学生的学号、姓名、总分和各科分数。
5程序编码
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct STU { int id;///学号 char name[20];///姓名 float score[20];///成绩 float rsum;///加权后的总分 float sum;///不加权的总分 }s[110]; int my_cmp(STU a,STU b) { if(a.rsum>=b.rsum)///按照加权后的总分来排序 { return 1; } else { return 0; } } void input(int n,int m) { int i,j; printf("请输入学生的学号、姓名和各科成绩\n"); for(i=0; i<n; i++) { scanf("%d",&s[i].id); scanf(" %s",&s[i].name); for(j=0; j<m; j++) { scanf("%f",&s[i].score[j]); } } } void quick_sort(int n) { sort(s,s+n,my_cmp);///STL库中的快速排序算法 } void ranks(int n,int rerank[]) { int i,k; k=0; for(i=0;i<n;i++) { if(s[i].rsum==s[i-1].rsum) { rerank[i]=k; } else { k++; rerank[i]=k; } } } void display(int n,int m,int rerank[]) { int i,j; printf("依次打印排名、学号、姓名、总分、加权总分和各科分数\n"); for(i=0; i<n; i++) { printf("%d ",rerank[i]); printf("%d ",s[i].id); printf("%s ",s[i].name); printf("%.2f ",s[i].sum); printf("%.2f ",s[i].rsum); for(j=0; j<m; j++) { printf("%.2f ",s[i].score[j]); } printf("\n"); } } int main() { int n,m,i,j; float ratios[30]; int rerank[100]; printf("请输入学生人数n:\n"); scanf("%d",&n); printf("请输入考试科目数m:\n"); scanf("%d",&m); printf("请依次输入各科的权重\n"); for(i=0; i<m; i++) { scanf("%f",&ratios[i]); } input(n,m); for(i=0; i<n; i++)///计算加权的总分和非加权的总分 { for(j=0; j<m; j++) { s[i].rsum+=s[i].score[j]*ratios[j]; s[i].sum+=s[i].score[j]; } } quick_sort(n); ranks(n,rerank); display(n,m,rerank); return 0; }
6 程序调试与测试
7 结果分析
该程序中学号定义为整型,姓名定义为字符串型,成绩定义为单浮点型并保留两位有效数字。错误输入会造成乱码和死循环的产生。该程序主要是基于结构体数组来实现排序和输出的,因而属于顺序表,遍历输出的时间复杂度是O(n),空间复杂度也是O(n)。排序所使用的快速排序时间复杂度是O(nlogn)~O(n^2),空间复杂度是O(logn)~O(n)。
8 总结
该程序能够实现按总分数高低次序打印出名次表(分数相同的为同一名次),按名次打印出每个学生的学号、姓名、总分以及各科成绩,同时还实现了给各科加权获得加权总分的附加功能。基本达到预期目标,但也存在着一些问题,因为使用的是顺序表类型的存储结构实现了随机存取,但在扩充空间上有着缺陷。该程序虽然简单,但却要从实际出发设计,设计的程序要贴近生活,比如在学校中出现成绩相同的学生必然有相同的名次,我们平时看到的成绩最多是小数点后两位等一系列问题,告诉我们写程序要贴近生活,从实际出发。