如何为关联分数的学生ID数组实现计数排序并同步ID位置
解决学生分数排序时ID同步绑定的问题
我明白你的痛点——你需要对学生的分数进行排序,同时让对应的学生ID牢牢绑定到分数的最终位置上,而不是单独排序分数导致ID和分数脱节。你尝试用计数排序但遇到了卡点,咱们一步步来搞定这个问题。
首先,先明确核心:我们不能只单独操作分数数组,必须把**学生ID和分数作为一个整体(也就是你的SResult结构体)**来进行排序,这样才能保证两者的对应关系不丢失。下面是调整后的计数排序实现,完全适配你的结构体场景:
完整实现代码
#include <stdio.h> #include <string.h> #include <stdlib.h> // 定义你的学生成绩结构体 struct SResult { char id[10]; // 假设ID长度足够容纳所有学生ID int score; }; // 针对结构体数组的计数排序(按分数升序) void countSortStudents(struct SResult arr[], int n) { // 第一步:确定分数的取值范围,找最大、最小值 int max_score = arr[0].score; int min_score = arr[0].score; for (int i = 1; i < n; i++) { if (arr[i].score > max_score) max_score = arr[i].score; if (arr[i].score < min_score) min_score = arr[i].score; } int score_range = max_score - min_score + 1; // 创建计数数组和临时输出数组 int* count_arr = (int*)calloc(score_range, sizeof(int)); struct SResult* output_arr = (struct SResult*)malloc(n * sizeof(struct SResult)); // 统计每个分数出现的次数 for (int i = 0; i < n; i++) { count_arr[arr[i].score - min_score]++; } // 将计数数组转换为前缀和,用来确定每个分数在输出数组中的最终位置 for (int i = 1; i < score_range; i++) { count_arr[i] += count_arr[i - 1]; } // 从后往前遍历原数组,把结构体元素放到输出数组的正确位置 // 从后往前是为了保证相同分数的学生保持原相对顺序(稳定排序) for (int i = n - 1; i >= 0; i--) { int target_idx = count_arr[arr[i].score - min_score] - 1; // 复制整个结构体(ID+分数)到输出数组 strcpy(output_arr[target_idx].id, arr[i].id); output_arr[target_idx].score = arr[i].score; count_arr[arr[i].score - min_score]--; } // 将排序后的结果复制回原数组 for (int i = 0; i < n; i++) { strcpy(arr[i].id, output_arr[i].id); arr[i].score = output_arr[i].score; } // 释放动态分配的内存 free(count_arr); free(output_arr); } // 测试函数 int main() { struct SResult sample[] = { {"A1234", 10}, {"A1239", 5}, {"A1394", 7}, {"A1434", 3}, {"A1454", 5}, {"A2884", 7}, {"A3235", 7}, {"A4334", 9}, {"A4884", 2}, {"A6934", 5}, {"A7265", 7}, {"A9559", 3} }; int student_count = sizeof(sample) / sizeof(sample[0]); printf("排序前:\n"); for (int i = 0; i < student_count; i++) { printf("ID: %s | 分数: %d\n", sample[i].id, sample[i].score); } countSortStudents(sample, student_count); printf("\n排序后(按分数升序):\n"); for (int i = 0; i < student_count; i++) { printf("ID: %s | 分数: %d\n", sample[i].id, sample[i].score); } return 0; }
关键注意点
- 绑定结构体整体操作:整个排序过程都是针对
SResult结构体进行的,而不是单独提取分数排序,这样ID和分数的对应关系从始至终不会断开。 - 字符串复制处理:因为结构体里的ID是字符数组,不能直接用
=赋值,必须用strcpy来完成ID的复制。 - 稳定排序保障:从后往前遍历原数组的操作,能让相同分数的学生保持他们在原数组中的相对顺序(比如原数组里先出现的5分学生,排序后依然排在同分数的前面),如果不需要稳定排序,也可以改成从前往后遍历。
- 降序排序调整:如果需要按分数降序排列,只需要修改计数数组的前缀和计算逻辑(从后往前累加),并调整遍历方向即可,具体修改可以参考代码里的注释思路。
内容的提问来源于stack exchange,提问作者user9510596




