数据结构实训——成绩统计系统

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{

数据对象DD是具有相同特征的数据元素的集合。各数据元素均含有类型相同,可唯一标识数据元素的关键字。

数据关系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("请输入学生的学号、姓名和各科成绩
");
    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("依次打印排名、学号、姓名、总分、加权总分和各科分数
");
    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("
");
    }
}

int main()
{
    int n,m,i,j;
    float ratios[30];
    int rerank[100];
    printf("请输入学生人数n:
");
    scanf("%d",&n);
    printf("请输入考试科目数m:
");
    scanf("%d",&m);
    printf("请依次输入各科的权重
");
    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 总结

该程序能够实现按总分数高低次序打印出名次表分数相同的为同一名次),按名次打印出每个学生的学号、姓名、总分以及各科成绩同时还实现了给各科加权获得加权总分的附加功能。基本达到预期目标,但也存在着一些问题,因为使用的是顺序表类型的存储结构实现了随机存取,但在扩充空间上有着缺陷。该程序虽然简单,但却要从实际出发设计,设计的程序要贴近生活,比如在学校中出现成绩相同的学生必然有相同的名次,我们平时看到的成绩最多是小数点后两位等一系列问题,告诉我们写程序要贴近生活,从实际出发。

 

 

 

 

原文地址:https://www.cnblogs.com/wkfvawl/p/10256902.html