C++ 竞赛教程

十、结构体

结构体允许把不同类型的相关数据组合成一个整体,比如把学生的姓名、年龄、分数打包在一起,是竞赛中组织复杂数据的核心工具。

定义结构体

结构体用 struct 关键字定义,把多个不同类型的数据字段打包成一种新的数据类型。定义好后可以像 intdouble 一样使用它来创建变量。

struct Student
{
  string name; // 姓名
  int age; // 年龄
  float score; // 分数
}; // ⚠️ 分号不能少!
↑ 这只是类型定义,不占内存
创建变量时才分配空间
Student s1
string name "小明"
int age 15
float score 92.5
⚠️
结构体定义末尾的分号 ; 必须写!这是初学者最容易遗漏的地方,缺少分号会导致编译错误,且错误提示通常很难看懂。
📌
三点说明:
① 结构体通常定义在 main() 之前,以便全局使用。
② 结构体只定义了一种新的数据类型,本身不占内存,只有用它创建变量时才分配空间。
③ 竞赛中常见的结构体:坐标点 Point、图的边 Edge、学生信息 Student 等。

使用结构体

定义好结构体后,可以像普通类型一样创建结构体变量,通过 .(点运算符)访问其成员。

点运算符:结构体变量 · 成员名
s1
.
name
"小明"
s1
.
age
15
s1
.
score
92.5
C++ · 结构体变量创建与访问
1// 方式1:先定义,再逐成员赋值
2Student s1;
3s1.name = "小明"; // 用 . 访问成员
4s1.age = 15;
5s1.score = 92.5;
6
7cout << "姓名:" << s1.name << endl;
8cout << "成绩:" << s1.score << endl;
9
10// 方式2:初始化时直接赋值(按成员定义顺序)
11Student s2 = {"小红", 14, 95.0}; // 顺序要与定义一致

结构体数组

可以用结构体数组存储多个同类型数据,每个元素都是一个完整的结构体变量,用 [i].成员名 访问。

students[0]
name"小明"
age15
score92.5
students[1]
name"小红"
age14
score95.0
students[2]
name"小华"
age16
score88.0
C++ · 结构体数组 & vector
1// 静态数组
2Student students[3] =
3{
4 {"小明", 15, 92.5},
5 {"小红", 14, 95.0},
6 {"小华", 16, 88.0}
7};
8
9// 遍历结构体数组
10for (int i = 0; i < 3; i++)
11 cout << students[i].name << ":" << students[i].score << endl;
12
13// 结合 vector(动态大小,竞赛中更常用)
14vector<Student> stuList;
15stuList.push_back({"小明", 15, 92.5});
16stuList.push_back({"小红", 14, 95.0});
17
18for (auto &s : stuList) // 范围 for 循环 + 引用
19 cout << s.name << " " << s.score << endl;

结构体与函数

结构体可以作为函数参数传递,同样分为值传递和引用传递两种方式。由于结构体往往包含多个字段,引用传递更为推荐,可避免昂贵的拷贝开销。

📋值传递(拷贝)
函数收到结构体的完整副本,修改不影响原对象。对于多字段结构体,拷贝开销较大。
void Print(Student s)
🔗引用传递(推荐)
函数直接操作原结构体,无拷贝开销。需要只读时加 const
void Update(Student &s)
C++ · 结构体作为函数参数
1// 值传递:函数内修改不影响原结构体
2void PrintStudent(Student s)
3{
4 cout << s.name << " " << s.score << endl;
5}
6
7// 引用传递:直接修改原结构体(推荐)
8void UpdateScore(Student &s, float newScore)
9{
10 s.score = newScore; // 直接修改原结构体
11}
12
13int main()
14{
15 Student s = {"小明", 15, 90.0};
16 PrintStudent(s); // 输出:小明 90
17 UpdateScore(s, 95.0); // 修改成绩
18 PrintStudent(s); // 输出:小明 95
19}
使用场景推荐方式
只需读取结构体内容const 引用const Student &s),避免拷贝开销
需要修改结构体内容普通引用Student &s
结构体很小(只有两三个基本类型字段)值传递也可以,开销可忽略

结构体与排序

竞赛中,结构体最常用的场景之一就是配合 sort() 进行自定义排序。需要提供一个比较函数 Cmp,告诉 sort 按什么规则排序。

按成绩从高到低排序的过程
排序前
[0]小明92.5
[1]小红95.0
[2]小华88.0
sort() + Cmp
排序后(成绩↓)
[0]小红95.0 🥇
[1]小明92.5 🥈
[2]小华88.0 🥉
// 比较函数:返回 true 表示 a 排在 b 前面
bool Cmp(const Student &a, const Student &b)
{
  return a.score > b.score; // 大于 → 成绩高的排前面(降序)
}
C++ · 结构体排序完整示例
1#include <algorithm>
2#include <vector>
3
4struct Student { string name; int age; float score; };
5
6// 自定义比较函数:成绩高的排前面
7bool Cmp(const Student &a, const Student &b)
8{ return a.score > b.score; }
9
10int main()
11{
12 vector<Student> v =
13 { {"小明",15,92.5}, {"小红",14,95.0}, {"小华",16,88.0} };
14
15 sort(v.begin(), v.end(), Cmp); // 传入比较函数
16
17 for (auto &s : v)
18 cout << s.name << ":" << s.score << endl;
19 // 输出:小红:95 小明:92.5 小华:88
20}
🏆
竞赛中 Cmp 函数的规则记忆:
return a.score > b.score → 成绩大的在前 → 降序
return a.score < b.score → 成绩小的在前 → 升序
多关键字排序:return a.score != b.score ? a.score > b.score : a.name < b.name(成绩不同按成绩降序,相同按姓名升序)