题目来自于博主算法大师的专栏:最新华为OD机试C卷+AB卷+OJ(C++JavaJSPy) https://blog.csdn.net/banxia_frontend/category_12225173.html
题目描述
小明来到某学校当老师,需要将学生按考试总分或单科分数进行排名,你能帮帮他吗?
输入描述
第 1 行输入两个整数,学生人数 n 和科目数量 m,0<n<100,0<m < 10
第 2 行输入 m 个科目名称,彼此之间用空格隔开。
- 科目名称只由英文字母构成,单个长度不超过 10 个字符。
- 科目的出现顺序和后续输入的学生成绩一一对应
- 不会出现重复的科目名称
第 3 行开始的 n 行,每行包含一个学生的姓名和该生 m 个科目的成绩 (空格隔开)。
- 学生不会重名
- 学生姓名只由英文字母构成,长度不超过 10 个字符
- 成绩是 0~100 的整数,依次对应第 2 行输入的科目
第 n+2 行,输入用作排名的科目名称。若科目不存在,则按总分进行排序。
输出描述
输出一行,按成绩排序后的学生名字,空格隔开。成绩相同的按照学生姓名字典顺序排序。
示例一
输入
3 2
yuwen shuxue
fangfang 95 90
xiaohua 88 95
minmin 100 82
shuxue
输出
xiaohua fangfang minmin
说明
按 shuxue 成绩排名,依次是 xiaohua、fangfang、minmin
思路
-
数据输入与初始化:
- 首先读取学生人数
n
和科目数量m
。 - 接着,读取并存储
m
个科目名称到二维数组subject
中。 - 初始化一个大小为
n
的结构体数组stu
,用于存放每个学生的姓名、各科成绩以及排序的关键字段(key)。 - 然后逐行读取每个学生的姓名和对应科目的成绩,并存入
stu
数组中。
- 首先读取学生人数
-
确定排序依据:
- 输入要进行排名的科目名称
sub
。 - 遍历科目列表,查找是否存在该科目。若存在,则将该科目的成绩作为排序依据,赋值给每个学生的
key
字段。 - 若未找到指定科目,则计算每个学生的总分,并用总分作为排序依据。
- 输入要进行排名的科目名称
-
排序:
- 使用 C 标准库中的
qsort
函数对stu
数组中的学生按照key
字段进行降序排列。这里定义了一个比较函数cmp
,当key
不同时按key
值排序,相同则按照学生姓名字典顺序升序排序。
- 使用 C 标准库中的
-
输出结果:
- 对排序后的
stu
数组,遍历并打印出所有学生的姓名,以空格隔开。
- 对排序后的
总结来说,通过接收用户输入的学生信息和排序要求,首先完成数据结构的构建和填充,然后根据题目需求选择合适的排序依据,最后利用快速排序算法实现对学生列表的排序,并按照题目要求的格式输出排名结果。
代码
无注释
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {char name[10];int scores[10];int key; // 用于排序的依据
} Students;int cmp(const void *a, const void *b) {Students *s1 = (Students *)a;Students *s2 = (Students *)b;if (s1->key != s2->key) {return s2->key - s1->key; // 降序}return strcmp(s1->name, s2->name);
}
int main() {int n, m;scanf("%d %d", &n, &m);char subject[m][11];for (int i = 0; i < m; i++) {scanf("%s", subject[i]);}Students stu[n];for (int i = 0; i < n; i++) {scanf("%s", stu[i].name);for (int j = 0; j < m; j++) {scanf("%d", &stu[i].scores[j]);}}char sub[11];scanf("%s", sub);int found = 0;for (int k = 0; k < m; k++) {if (strcmp(subject[k], sub) == 0) {found = 1;for (int i = 0; i < n; i++) {stu[i].key = stu[i].scores[k];}break;}}if (found == 0) {for (int i = 0; i < n; i++) {stu[i].key = 0;for (int j = 0; j < m; j++) {stu[i].key += stu[i].scores[j];}}}qsort(stu, n, sizeof(Students), cmp);for (int i = 0; i < n; i++) {printf("%s ", stu[i].name);}printf("\n");return 0;
}
有注释
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 定义学生结构体,包含姓名、各科成绩以及用于排序的关键字段(key)
typedef struct {char name[10]; // 存储学生姓名int scores[10]; // 存储每个学生的各科成绩int key; // 用于根据指定科目成绩或总分进行排序的依据
} Students;// 定义比较函数,用于qsort排序。a和b是需要比较的两个学生结构体指针
int cmp(const void *a, const void *b) {Students *s1 = (Students *)a;Students *s2 = (Students *)b;// 比较key字段,按照降序排列if (s1->key != s2->key) {return s2->key - s1->key;}// 若key相同,则按照学生姓名字典顺序升序排列return strcmp(s1->name, s2->name);
}int main() {int n, m; // 分别存储学生人数和科目数量scanf("%d %d", &n, &m); // 输入学生人数和科目数量// 存储科目名称的二维数组char subject[m][11];for (int i = 0; i < m; i++) {scanf("%s", subject[i]); // 读取每门科目的名称}// 初始化学生数组Students stu[n];// 读取每个学生的姓名和各科成绩for (int i = 0; i < n; i++) {scanf("%s", stu[i].name); // 读取学生姓名for (int j = 0; j < m; j++) {scanf("%d", &stu[i].scores[j]); // 读取单科成绩}}// 读取用于排名的科目名称char sub[11];scanf("%s", sub);int found = 0; // 标记是否找到用于排序的科目for (int k = 0; k < m; k++) {if (strcmp(subject[k], sub) == 0) { // 如果输入的科目存在于科目列表中found = 1;// 将对应科目的成绩作为排序依据赋值给每个学生的key字段for (int i = 0; i < n; i++) {stu[i].key = stu[i].scores[k];}break;}}// 如果未找到指定科目,则以总分为排序依据if (found == 0) {for (int i = 0; i < n; i++) {stu[i].key = 0; // 初始化总分为0// 计算每个学生的总分,并赋值给key字段for (int j = 0; j < m; j++) {stu[i].key += stu[i].scores[j];}}}// 使用qsort对整个学生数组进行排序qsort(stu, n, sizeof(Students), cmp);// 输出排序后的学生姓名列表for (int i = 0; i < n; i++) {printf("%s ", stu[i].name);}printf("\n"); // 输出换行符以结束输出return 0; // 程序正常结束
}