C++ 结构体与结构体数组详解:定义、排序与实战应用
导读在实际开发中我们经常需要把多个不同类型的数据绑定在一起表示一个实体——比如一个学生的学号int、姓名string、成绩double。C 的struct就是做这件事的。本文从结构体的定义讲起逐步扩展到结构体数组、结构体排序最后通过三道经典题目演示结构体在实战中的应用。一、结构体是什么C 内置的类型int、double、string一次只能存一个值。但现实中的数据往往是一组一组出现的一个学生有学号、姓名、年龄、成绩等多个属性一个坐标有 x 和 y 两个值。**结构体struct**就是把多个不同类型的变量打包成一个自定义类型// 定义一个学生结构体structstudent{intnum;// 学号string name;// 姓名intage;// 年龄doublescore;// 成绩};定义完成后student就和int、string一样是一个可用的类型了。C vs C 小知识C 语言中习惯用typedef struct student {} student;来简化命名。C 中直接写struct student {}就行typedef可以省略使用时也不需要加struct关键字。二、创建和使用结构体变量2.1 用结构体类型创建变量定义好结构体后可以像内置类型一样创建变量student st;// 创建一个学生变量st.num1001;// 用 . 访问成员st.name张三;st.age20;st.score95.5;st.num就像张三的学号.运算符用来访问结构体内部的某个字段。2.2 创建时直接初始化也可以在创建的同时赋值student st{1002,李四,21,88.0};字段按照定义顺序依次赋值不想赋值的可以留空默认初始化为 0 或空字符串。2.3 用typedef给结构体起别名如果嫌struct student写起来太长可以用typedef起个短名字typedefstructstudent{intnum;string name;intage;doublescore;}stu;// stu 就是 struct student 的别名stu st1;// 和 student st1; 等价stu st2;三、结构体数组把多个对象放在一起一个student变量只能存一个学生的信息。如果要存全班 50 个学生呢这就需要结构体数组。3.1 普通数组形式stu arr[50];// 创建一个能存 50 个学生的数组// 访问第 i 个学生的学号arr[0].num1001;arr[1].name王五;和普通数组一样用[]取下标然后.取字段。3.2 vector 形式推荐实际开发中更推荐用vector因为大小可以动态调整vectorstuvec;// 创建一个临时变量填充数据后 push 进去stu s;s.num1001;s.name张三;s.score95.5;vec.push_back(s);// 也可以直接在 push_back 时用花括号构造C11vec.push_back({1002,李四,21,88.0});技巧如果数据量已知可以直接创建指定大小的 vectorvectorstu vec(50); // 预分配 50 个位置每个字段默认初始化 vec[1].num 1001;3.3 遍历结构体 vector// 增强 for 循环遍历for(autos:vec){couts.num s.name s.scoreendl;}用引用避免拷贝提高效率。四、结构体排序sort lambda 表达式这是结构体最实用的考点。实际题目中我们经常需要对学生按成绩排序、对坐标按 x 排序等等。关键在于怎么告诉sort按结构体的哪个字段来排4.1 基本用法用 lambda 表达式指定排序规则vectorstuvec{{1001,张三,20,95.5},{1002,李四,21,88.0},{1003,王五,19,92.0}};// 按成绩从高到低排序sort(vec.begin(),vec.end(),[](conststua,conststub){returna.scoreb.score;// a 的成绩 b 的成绩时a 排在前面});lambda 表达式的规则很简单参数是两个待比较的元素a和breturn true表示a应该排在b前面。4.2 多字段排序实际题目经常要求成绩相同则按学号排这种多级排序// 先按成绩降序成绩相同则按学号升序sort(vec.begin(),vec.end(),[](conststua,conststub){if(a.score!b.score)returna.scoreb.score;returna.numb.num;});逻辑是先比第一个字段如果相等再比第二个字段以此类推。用if逐级判断即可。五、实战题目5.1 谁考了第 k 名题目输入 n 个学生的学号和成绩按成绩从高到低排序后输出第 k 名的学号和成绩。思路用结构体存学号和成绩排序后直接取第 k-1 个元素。#includebits/stdc.husingnamespacestd;structstu{string num;// 学号doublescore;// 成绩};vectorstuvec;intmain(){intn,k;cinnk;for(inti0;in;i){stu s;cins.nums.score;vec.push_back(s);}// 按成绩降序排序sort(vec.begin(),vec.end(),[](conststua,conststub){returna.scoreb.score;});// 第 k 名就是下标 k-1下标从 0 开始coutvec[k-1].num vec[k-1].score;return0;}关键点结构体只定义需要的字段不要贪多。这道题只需要学号和成绩就不用加 name 和 age。5.2 奖学金题目输入 n 个学生的语文、数学、英语成绩计算总分后按以下规则排序取前 5 名总分高的在前总分相同语文成绩高的在前总分和语文都相同学号小的在前这是一道经典的三级排序题排序规则稍微复杂但逻辑清晰。思路结构体里存学号、各科成绩和总分用 lambda 实现三级排序。#includebits/stdc.husingnamespacestd;structsc{intnum;// 学号intchin;// 语文intmath;// 数学inteng;// 英语intscore;// 总分};vectorscvec;intmain(){intn;cinn;for(inti1;in;i){sc s;s.numi;cins.chins.maths.eng;s.scores.chins.maths.eng;// 计算总分vec.push_back(s);}// 三级排序总分 - 语文 - 学号sort(vec.begin(),vec.end(),[](constsca,constscb){if(a.score!b.score)returna.scoreb.score;if(a.chin!b.chin)returna.chinb.chin;returna.numb.num;});// 输出前 5 名for(inti0;i5;i){coutvec[i].num vec[i].scoreendl;}return0;}关键点多级排序时每一级判断完!后再进入下一级这样逻辑最清晰不会出错。5.3 合并区间LeetCode 56题目给定若干个区间[start, end]将所有有重叠的区间合并。虽然这道题用的是vectorvectorint而非自定义结构体但它的核心思路和结构体排序完全一致——先按某个字段排序再遍历处理。思路先按区间左端点排序然后遍历判断相邻区间是否重叠。重叠则合并取更大的右端点不重叠则直接加入结果。classSolution{public:vectorvectorintmerge(vectorvectorintintervals){if(intervals.empty())returnintervals;// 按区间左端点升序排序sort(intervals.begin(),intervals.end(),[](constvectorinta,constvectorintb){returna[0]b[0];});vectorvectorintresult;result.push_back(intervals[0]);// 先把第一个区间放进去for(inti1;iintervals.size();i){// 当前区间的左端点 结果中最后一个区间的右端点 → 重叠if(intervals[i][0]result.back()[1]){// 合并取更大的右端点result.back()[1]max(result.back()[1],intervals[i][1]);}else{// 不重叠直接加入结果result.push_back(intervals[i]);}}returnresult;}};关键点result.back()取的是结果中最后一个区间用它来判断是否和当前区间重叠。这种先排序再贪心合并的思路在很多区间类题目中都适用。六、总结知识点关键内容结构体定义struct 名字 { 字段... };不同类型数据打包成员访问用.运算符st.name结构体数组普通数组stu arr[N]或vectorstu结构体排序sort lambda 表达式指定比较字段多级排序if (字段1 ! 字段1) return 比较; if (字段2 ! 字段2) return 比较;typedeftypedef struct xxx {} 别名;简化类型名结构体是 C 中连接数据和逻辑的桥梁。后续学习链表、二叉树等数据结构时节点本质上就是结构体。把结构体用熟练后面的内容会轻松很多。