1. 题目背景与需求分析
这道PTA平台的L1-005题目要求我们处理考生信息与座位号的对应关系。从实际考试场景来看,每个考生会有三个关键信息:
- 准考证号(14位数字)
- 试机座位号(考试前模拟测试使用的座位)
- 考试座位号(正式考试时的座位)
题目会给出N个考生的完整信息,然后要求我们根据查询的试机座位号,快速找到对应的准考证号和考试座位号。这本质上是一个典型的键值查询问题,试机座位号作为key,需要返回对应的完整考生信息。
注意:14位准考证号已经超出int类型的存储范围(2^31-1≈21亿),必须用字符串或long long类型存储。这是本题的第一个关键点。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据结构设计与选择
2.1 结构体定义方案
最直观的解决方案是定义考生结构体:
c复制typedef struct {
char id[15]; // 准考证号(14位+'\0')
int testSeat; // 试机座位号
int examSeat; // 考试座位号
} Student;
这样设计的优势:
- 内存连续,访问效率高
- 三个字段逻辑关联清晰
- 适合后续的数组存储
2.2 替代方案对比
方案二:使用三个独立数组
c复制char ids[N][15];
int testSeats[N];
int examSeats[N];
缺点:数据关联性差,容易出错
方案三:使用链表
不适用本题,因为:
- 题目没有插入删除操作
- 链表查询效率O(n)低于数组O(1)
3. 核心算法实现
3.1 输入处理流程
完整处理流程如下:
- 读取考生数量N
- 创建Student数组
- 循环读取N个考生信息
- 读取查询数量M
- 循环处理M个查询
关键代码段:
c复制int N, M;
scanf("%d", &N);
Student students[N];
for(int i=0; i<N; i++){
scanf("%s %d %d", students[i].id, &students[i].testSeat, &students[i].examSeat);
}
3.2 查询优化策略
直接遍历查找(O(M*N)):
c复制for(int i=0; i<M; i++){
int query;
scanf("%d", &query);
for(int j=0; j<N; j++){
if(students[j].testSeat == query){
printf("%s %d\n", students[j].id, students[j].examSeat);
break;
}
}
}
更优方案(O(N+M)):
- 预处理创建哈希表(试机号→数组下标)
- 查询时直接索引
c复制int maxSeat = 0;
for(int i=0; i<N; i++){
if(students[i].testSeat > maxSeat){
maxSeat = students[i].testSeat;
}
}
int hash[maxSeat+1];
for(int i=0; i<N; i++){
hash[students[i].testSeat] = i;
}
for(int i=0; i<M; i++){
int query;
scanf("%d", &query);
int index = hash[query];
printf("%s %d\n", students[index].id, students[index].examSeat);
}
4. 边界条件与异常处理
4.1 输入验证
必须处理的情况:
- N的范围(题目通常给出,如N≤1000)
- 准考证号长度验证
- 座位号唯一性检查
示例代码:
c复制if(N <=0 || N >1000){
printf("Invalid N!\n");
return -1;
}
for(int i=0; i<N; i++){
if(strlen(students[i].id) != 14){
printf("Invalid ID length!\n");
return -1;
}
}
4.2 内存管理
栈内存限制:
- 大数组可能导致栈溢出(如N=1e6时)
- 解决方案:改用动态内存分配
c复制Student *students = (Student*)malloc(N * sizeof(Student));
// ...使用后
free(students);
5. 性能优化技巧
5.1 输入输出加速
对于大规模数据(N>1e5):
c复制// 在main函数开头添加
setvbuf(stdin, NULL, _IOFBF, 4096);
setvbuf(stdout, NULL, _IOFBF, 4096);
5.2 查询预处理
空间换时间策略:
- 试机座位号范围已知时,直接用数组索引
- 范围较大时,使用哈希表
c复制// 假设试机号范围1~1000
Student* seatMap[1001] = {NULL};
for(int i=0; i<N; i++){
seatMap[students[i].testSeat] = &students[i];
}
6. 完整参考代码
c复制#include <stdio.h>
#include <string.h>
typedef struct {
char id[15];
int testSeat;
int examSeat;
} Student;
int main() {
int N, M;
scanf("%d", &N);
Student students[N];
int maxSeat = 0;
for(int i = 0; i < N; i++) {
scanf("%s %d %d", students[i].id, &students[i].testSeat, &students[i].examSeat);
if(students[i].testSeat > maxSeat) {
maxSeat = students[i].testSeat;
}
}
int hash[maxSeat + 1];
for(int i = 0; i < N; i++) {
hash[students[i].testSeat] = i;
}
scanf("%d", &M);
for(int i = 0; i < M; i++) {
int query;
scanf("%d", &query);
int index = hash[query];
printf("%s %d\n", students[index].id, students[index].examSeat);
}
return 0;
}
7. 常见错误与调试技巧
7.1 典型错误案例
错误1:准考证号用int存储
c复制long long id; // 错误!14位可能超出long long精度
错误2:数组越界
c复制char id[14]; // 错误!需要15字节(14位+'\0')
错误3:哈希表未初始化
c复制int hash[maxSeat+1]; // 需要确保maxSeat正确计算
7.2 PTA提交注意事项
- 必须删除所有调试输出
- 严格匹配输出格式(空格、换行)
- 变量命名避免使用保留字
- 时间复杂度限制(本题O(N+M)可通过)
8. 扩展思考与变式
8.1 多条件查询变式
如果题目改为:
- 同时支持试机号和考试号查询
- 需要处理10^5量级数据
解决方案:
- 构建两个哈希表
- 使用数据库式索引
c复制typedef struct {
char id[15];
int testSeat;
int examSeat;
} Student;
Student *testHash[MAX_TEST_SEAT];
Student *examHash[MAX_EXAM_SEAT];
8.2 动态更新场景
如果需要支持插入、删除操作:
- 改用平衡二叉搜索树
- 或使用哈希表+链表
c复制typedef struct Node {
Student data;
struct Node *next;
} Node;
Node *hashTable[HASH_SIZE];
9. 实际工程应用
类似场景:
- 学籍管理系统
- 考场安排系统
- 机票预订系统(票号↔座位号)
工程优化方向:
- 数据持久化(文件/数据库)
- 网络通信支持
- 多线程查询处理
10. 学习路线建议
进一步学习:
- 《数据结构与算法分析》哈希表章节
- PTA L1相关题目训练
- 标准库中的qsort、bsearch使用
推荐练习题目:
- L1-003 个位数统计
- L1-007 念数字
- L1-011 A-B
