数据结构实训——成绩统计系统
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)///按照加权后的总分来排序
{
return1;
}
else
{
return0;
}
}
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);
return0;
}
6 程序调试与测试
7 结果分析
该程序中学号定义为整型,姓名定义为字符串型,成绩定义为单浮点型并保留两位有效数字。错误输⼊会造成乱码和死循环的产⽣。该程序主要是基于结构体数组来实现排序和输出的,因⽽属于顺序表,遍历输出的时间复杂度是O(n),空间复杂度也是O(n)。排序所使⽤的快速排序时间复杂度是O(nlogn)~O(n^2),空间复杂度是O(logn)~O(n)。
8 总结
该程序能够实现按总分数⾼低次序打印出名次表(分数相同的为同⼀名次),按名次打印出每个学⽣的学号、姓名、总分以及各科成绩,同
时还实现了给各科加权获得加权总分的附加功能。基本达到预期⽬标,但也存在着⼀些问题,因为使⽤的是顺序表类型的存储结构实现了随机存取,但在扩充空间上有着缺陷。该程序虽然简单,但却要从实际出发设计,设计的程序要贴近⽣活,⽐如在学校中出现成绩相同的学⽣必然有相同的名次,我们平时看到的成绩最多是⼩数点后两位等⼀系列问题,告诉我们写程序要贴近⽣活,从实际出发。