首页 / 生活随笔 / 正文 C++的“日历”排序:精通 `std::sort` 排序自定义日期 2026-01-21 1 30 min 在C++编程中,排序是一个核心任务。`std::sort`(来自 ``)是一个极其强大的“**神奇黑盒**”,可以为你排序 `vector`。 * `vector nums = {50, 10, 30};` * `std::sort(nums.begin(), nums.end());` -\> `nums` 变成 `{10, 30, 50}` (从小到大)。 * `vector names = {"Charlie", "Alice"};` * `std::sort(names.begin(), names.end());` -\> `names` 变成 `{"Alice", "Charlie"}` (按字母顺序)。 **但是,如果你有一堆“日期”字符串呢?** `vector dates = {"10-12-2023", "05-01-2024"};` 如果你“天真地”调用 `std::sort`: `std::sort(dates.begin(), dates.end());` * 结果会是:`{"05-01-2024", "10-12-2023"}`。 * **这是错误的!** 2024年的日期排在了2023年的**前面**! **一个简单的比喻:“字典” vs “日历”** * **默认 `std::sort` (用于字符串)**:就像一个“**字典**”。它**只**懂“**字母顺序**”。在“字典”里,`"0"` (以 '0' 开头) **确实**排在 `"1"` (以 '1' 开头) 的**前面**。 * **你想要的(日期排序)**:就像一个“**日历**”。你需要一种“**智能**”排序,它能**理解** `Year` (年), `Month` (月), `Day` (日) 的**逻辑关系**。 **解决方案:** 我们不能直接排序字符串。我们必须: 1. **“教会” C++ 如何“阅读”日期**。最好的方法是创建一个“**自定义盒子**”(`struct`),把日期拆分成“年”、“月”、“日”三个整数。 2. **“教会” `std::sort` 我们的“日历规则”**。我们必须提供一个“**自定义比较器**”(Comparator)函数,告诉 `std::sort`:“**先比较年份,如果年份相同,再比较月份...**” **在本教程中,你将学会:** * `✅` **为什么不能直接排日期字符串**(“字典” vs “日历”)。 * `✅` **如何使用 `struct`** 来“打包”日期数据 (Y, M, D)。 * `✅` **“黄金法则”**:如何编写一个“**自定义比较器**”函数 (Comparator)。 * `✅` **`std::sort` 的“第三个参数”**:如何把你的“规则”传递给 `std::sort`。 * `✅` **实战演练**:编写一个完整的 `sortDates` 程序。 * `✅` **“X光透视”**:用调试器“亲眼目睹” `std::sort` 是如何“调用”你的“自定义规则”的。 **前置知识说明 (100% 自洽):** * **变量 (Variable)**:理解存储数据的“盒子”,如 `int year = 2024;`。 * **`vector` (向量)**:C++标准库提供的一种“动态数组”(“魔法弹性盒子列表”)。你需要 `#include `。 * **`struct` (结构体)**:一种“蓝图”,用于创建“自定义盒子”,把相关数据(如 `y`, `m`, `d`)打包在一起。 * **`#include `**:`std::sort` “神奇黑盒”所在的“工具包”。 * **`bool` 函数**:一个返回 `true` (真) 或 `false` (假) 的函数,我们将用它来编写“规则”。 * **`if/else if/else`**:用于编写“规则”的逻辑判断。 * **编译 (Compile)**:C++代码(“食谱”)必须被“编译”(“烘焙”),才能变成电脑可执行的程序(“蛋糕”)。 --- ### **第一部分:“自定义盒子”—— `Date` 结构体** 首先,我们“设计”一个“蓝图”,告诉C++一个 `Date` 对象长什么样。 ```cpp #include #include #include // 包含 std::sort #include using namespace std; // “蓝图”:一个自定义的 Date 盒子 // 它把日期“拆分”成三个 *可比较* 的整数 struct Date { int day; int month; int year; }; ``` 现在,我们可以创建 `Date` 对象的 `vector`,而不是 `string` 的 `vector`: `vector calendar = { {10, 12, 2023}, {5, 1, 2024}, {15, 12, 2023} };` --- ### **第二部分:“日历规则”——自定义比较器** `std::sort` 的“默认规则”是 `operator<` (小于号)。我们现在要提供一个**新**的“规则手册”(一个函数),来代替 `<`。 **比较器 (Comparator) 的“黄金法则”:** `std::sort` 需要一个函数 `bool compare(A, B)`。 * 如果你希望 `A` **排在** `B` 的**前面**,你的函数必须返回 **`true`**。 * 如果你希望 `A` **排在** `B` 的**后面**(或相同),你的函数必须返回 **`false`**。 **`compareDates.cpp` (“日历规则”函数)** ```cpp // “规则手册”:告诉 std::sort 如何比较两个 Date 对象 bool compareDates(const Date& a, const Date& b) { // 规则 1:先比较“年” if (a.year < b.year) { return true; // a 的年份小,a 应该排在前面 } if (a.year > b.year) { return false; // a 的年份大,a 应该排在后面 } // “行内预警”:如果程序运行到这里,说明 a.year == b.year // 规则 2:如果年份相同,再比较“月” if (a.month < b.month) { return true; // a 的月份小,a 应该排在前面 } if (a.month > b.month) { return false; // a 的月份大,a 应该排在后面 } // “行内预警”:如果程序运行到这里,说明年份和月份都相同 // 规则 3:如果月份相同,最后比较“日” return (a.day < b.day); // 如果 a.day 小,返回 true } ``` --- ### **第三部分:“实战演练”——结合 `sort` 与“规则”** 现在我们把 `std::sort` 和我们的“规则手册” `compareDates` 结合起来。 **`date_sort.cpp` (完整代码)** ```cpp #include #include #include #include using namespace std; // --- 1. “蓝图” --- struct Date { int day; int month; int year; }; // --- 2. “规则手册” --- bool compareDates(const Date& a, const Date& b) { if (a.year < b.year) return true; if (a.year > b.year) return false; // 年份相同 if (a.month < b.month) return true; if (a.month > b.month) return false; // 月份也相同 return (a.day < b.day); } // 辅助函数:打印日期 void printDates(const string& title, const vector& dates) { cout << title << endl; for (const auto& d : dates) { // (为了美观,我们补 0) printf(" %02d-%02d-%04d\n", d.day, d.month, d.year); } } int main() { // 3. 创建“自定义盒子”列表 vector calendar = { {10, 12, 2023}, // 10-Dec-2023 {5, 1, 2024}, // 05-Jan-2024 {15, 12, 2023}, // 15-Dec-2023 {2, 2, 2023} // 02-Feb-2023 }; printDates("--- 原始顺序 ---", calendar); // 4. “按下按钮”并“递上纸条” (规则手册) std::sort(calendar.begin(), calendar.end(), compareDates); printDates("\n--- 日历排序后 ---", calendar); return 0; } ``` **“手把手”终端模拟:** ```powershell PS C:\MyCode> g++ date_sort.cpp -o date_sort.exe -std=c++11 PS C:\MyCode> .\date_sort.exe --- 原始顺序 --- 10-12-2023 05-01-2024 15-12-2023 02-02-2023 --- 日历排序后 --- 02-02-2023 10-12-2023 15-12-2023 05-01-2024 ``` **顿悟时刻:** 排序**成功**!`std::sort` 正确地理解了我们的“日历规则”,将 2023 年的日期排在了 2024 年的前面。 --- ### **第四部分:“X光透视”——亲眼目睹“规则”被调用** 我们无法(也不需要)用调试器“步入” (`F11`) `std::sort` 内部,因为它是一个高度优化的、编译好的“黑盒”。 但是,我们可以“步入”它**调用我们**的“自定义规则” (`compareDates`)! #### **“X光”实战(基于 `date_sort.cpp`)** 1. **设置断点:** * **动作:** 在VS Code中,把你的鼠标移动到\*\*“规则手册”**函数 `compareDates` 内部的**第16行\*\*(`if (a.year < b.year)`)的**行号左边**。 * **点击**那个小 red dot,设置一个**断点**。 2. **启动“子弹时间”(F5):** * **动作:** 按下 `F5` 键。 * **你会看到:** 程序执行 `main`,创建 `vector`,打印“原始顺序”。 * 当程序执行到 `std::sort(...)` 这一行时,它会\*\*“跳进”**你的 `compareDates` 函数,**“冻结”\*\*在第16行! 3. **开启“X光”(观察“裁判”工作):** * **动作:** 仔细看那个“变量”(VARIABLES)窗口。 * **你会看到:** * `a: {day: 5, month: 1, year: 2024}` * `b: {day: 10, month: 12, year: 2023}` * **顿悟时刻:** `std::sort`(“黑盒”)为了决定 "2024年" 和 "2023年" 谁该排前面,它把**这两个**对象“递”给了你的“裁判” (`compareDates`)! * **动作:** 按下 `F10` 键(“Step Over”)。 * **你会看到:** `(a.year < b.year)` (即 `2024 < 2023`) 计算为 `false`。高亮条跳到**第19行**。 * **动作:** 按下 `F10` 键。 * **你会看到:** `(a.year > b.year)` (即 `2024 > 2023`) 计算为 `true`。函数返回 `false`。`sort` 知道了 "2024" 应该在 "2023" 后面。 4. **继续执行 (F5)。** 5. **第二次“冻结” (在 `compareDates` 内部):** * **动作:** 按下 `F5` 键,程序会**再次**停在 `compareDates` 断点处。 * **观察“变量”窗口:** * `a: {day: 15, month: 12, year: 2023}` * `b: {day: 10, month: 12, year: 2023}` * **顿悟时刻:** `std::sort` 现在正在比较两个**同年份**的日期! * **动作:** 按下 `F10` 键(`if (a.year < b.year)` -\> `false`)。 * **动作:** 按下 `F10` 键(`if (a.year > b.year)` -\> `false`)。 * **(关键!)** 高亮条移动到**第24行**(比较月份)。 * **动作:** 按下 `F10` 键(`if (a.month < b.month)` (`12 < 12`) -\> `false`)。 * **动作:** 按下 `F10` 键(`if (a.month > b.month)` (`12 > 12`) -\> `false`)。 * **动作:** 按下 `F10` 键(`return (a.day < b.day)` (`15 < 10`) -\> `false`)。 * **顿悟时刻:** `sort` 知道了 "15号" 应该在 "10号" 后面。 6. **(继续按 F5,`sort` 会调用你的“裁判”很多次...)** --- ### **动手试试!(终极挑战:你的“学生排名器”)** 现在,你来当一次“教务处”老师。 **任务:** 1. **设计一个 `Student` 结构体**: * `string name;` * `int score;` (分数) * `int age;` 2. **创建**一个 `vector` 并填入一些数据。 3. **编写一个“规则手册”**:`bool compareStudents(const Student& a, const Student& b)`。 4. **(关键)** 排序规则是: * 1. 优先按**分数 (`score`) 降序**(分数高的排前面)。 * 2. 如果分数**相同**,则按**年龄 (`age`) 升序**(年龄小的排前面)。 5. **调用** `std::sort`,传入你的“规则手册”。 6. **打印**排序后的学生列表。 **`student_sort.cpp` (你的 TODO):** ```cpp #include #include #include #include using namespace std; // --- TODO 1: Student 结构体 --- struct Student { string name; int score; int age; }; // --- TODO 3 & 4: 编写 *新* 的“规则” --- // (按分数降序, 同分按年龄升序) // bool compareStudents(const Student& a, const Student& b) { // // 1. 先比较分数 // if (a.score > b.score) return true; // 分数高,排前面 // if (a.score < b.score) return false; // 分数低,排后面 // // 2. 如果分数相同 (a.score == b.score) // // 再比较年龄 (升序) // // return a.age < b.age; // 年龄小,排前面 // } int main() { // --- TODO 2: 创建数据 --- vector students = { {"Alice", 90, 20}, {"Bob", 85, 22}, {"Charlie", 90, 19}, // <-- 和 Alice 同分 {"David", 70, 21} }; cout << "--- 原始列表 ---" << endl; // (在此处添加 for 循环打印) // --- TODO 5: 调用 sort --- // std::sort(students.begin(), students.end(), ...); cout << "\n--- 排序后 ---" << endl; // --- TODO 6: 打印结果 --- // (在此处添加 for 循环打印) // 预测:Charlie (90, 19) 应该在 Alice (90, 20) 之前 return 0; } ``` > 这个挑战让你实践了如何编写一个“**多级**”比较规则,这是 `std::sort` 在真实项目中极其常见的用法! > 标签:C++ 分享: ← 上一篇 C++的“动态表格”:精通 `vector<vector<T>>` (二维向量) 下一篇 支持 eSIM卡的设备列表:安卓手机,苹果iPhone手机,iPad设备,笔记本电脑 → 相关推荐 C++的“动态表格”:精通 `vector<vector<T>>` (二维向量) 2026-01-21 💬 评论 😊 😀 😂 😊 😍 🥰 😎 🤔 👍 👏 🎉 ❤️ 🔥 ✨ 💯 😢 🙏 💪 👀 🌟 💖 🌈 提交评论