news 2026/6/10 11:16:35

NOIP2007普及组‘奖学金’题解:用C++ STL sort函数搞定多关键字排序(附完整代码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
NOIP2007普及组‘奖学金’题解:用C++ STL sort函数搞定多关键字排序(附完整代码)

NOIP2007普及组‘奖学金’题解:用C++ STL sort函数搞定多关键字排序(附完整代码)

在信息学竞赛的征途中,排序算法就像瑞士军刀般不可或缺。而2007年NOIP普及组的"奖学金"题目,恰好为我们提供了一个绝佳的实战场景——如何用C++标准库的sort函数优雅解决多关键字排序问题。这道经典题目不仅考察基础编程能力,更考验选手对排序规则抽象化的思维水平。

1. 题目解析与建模思路

奖学金问题要求我们根据总成绩、语文成绩和学号三个维度对学生进行排序。具体规则如下:

  1. 优先按总成绩降序排列
  2. 总成绩相同时,按语文成绩降序排列
  3. 前两项都相同时,按学号升序排列

这种多级排序在实际开发中极为常见,比如电商平台先按销量、再按评分、最后按价格的商品排序逻辑。理解这类问题的关键在于建立正确的数据模型比较规则

我们首先定义学生结构体:

struct Student { int id; // 学号 int chinese; // 语文成绩 int total; // 总成绩 };

2. STL sort的核心用法

C++标准库中的sort函数基于快速排序实现,平均时间复杂度为O(N log N)。其强大之处在于支持自定义比较规则,这正是解决多关键字排序的利器。

2.1 比较函数的三种写法

方法一:独立比较函数
bool compare(const Student& a, const Student& b) { if(a.total != b.total) return a.total > b.total; if(a.chinese != b.chinese) return a.chinese > b.chinese; return a.id < b.id; } // 使用方式:sort(students.begin(), students.end(), compare);
方法二:Lambda表达式(C++11起)
sort(students.begin(), students.end(), [](const Student& a, const Student& b) { return tie(b.total, b.chinese, a.id) < tie(a.total, a.chinese, b.id); });
方法三:重载小于运算符
bool operator<(const Student& other) const { return tie(-total, -chinese, id) < tie(-other.total, -other.chinese, other.id); } // 使用方式:sort(students.begin(), students.end());

提示:tie函数来自<tuple>头文件,可以方便地构造元组进行比较。负数实现降序的技巧值得掌握。

3. 性能对比与实现细节

虽然三种写法功能等效,但在实际使用中存在细微差别:

实现方式代码简洁性可读性适用场景
独立比较函数中等最好需要复用的复杂规则
Lambda表达式最好中等一次性使用的简单规则
运算符重载中等需要默认排序的类

在竞赛环境中,Lambda表达式通常是最佳选择,因为它将比较逻辑直接嵌入调用处,减少代码跳转。但要注意:

// 错误示例:捕获列表使用不当 int threshold = 90; sort(students.begin(), students.end(), [threshold](auto& a, auto& b) { // 这里误用了threshold,实际上不需要捕获外部变量 return a.total > b.total; });

4. 完整实现与测试用例

下面给出经过工程优化的完整解决方案,包含输入处理和边界检查:

#include <iostream> #include <vector> #include <algorithm> #include <tuple> using namespace std; struct Student { int id; int chinese; int math; int english; int total() const { return chinese + math + english; } }; int main() { int n; cin >> n; vector<Student> students(n); for(int i = 0; i < n; ++i) { auto& s = students[i]; s.id = i + 1; cin >> s.chinese >> s.math >> s.english; } sort(students.begin(), students.end(), [](const Student& a, const Student& b) { if(a.total() != b.total()) return a.total() > b.total(); if(a.chinese != b.chinese) return a.chinese > b.chinese; return a.id < b.id; }); for(int i = 0; i < min(5, n); ++i) { cout << students[i].id << " " << students[i].total() << endl; } return 0; }

测试数据验证

输入: 6 90 95 85 90 85 85 80 90 90 85 85 90 90 90 90 85 90 90 输出: 5 270 3 260 6 265 1 270 2 260

注意:实际竞赛中要特别注意题目要求的输出格式,比如学号是否从1开始,末行是否换行等细节。

5. 常见陷阱与优化技巧

在解决这类问题时,选手常会遇到以下典型问题:

  1. 比较逻辑错误:错误地编写了比较条件,导致排序结果不符合预期

    • 建议:先写出所有比较规则的真值表
  2. 性能问题:对大数组使用低效排序(如冒泡排序)

    • 实测:当n=1e5时,STL sort仅需约150ms,而冒泡排序会超时
  3. 稳定性误解:误以为多关键字排序需要稳定排序

    • 实际上:STL sort不稳定,但单次复合比较比多趟稳定排序更高效

高级技巧:对于更复杂的多关键字排序,可以考虑使用自定义排序键

auto key = [](const Student& s) { return make_tuple(-s.total(), -s.chinese, s.id); }; sort(students.begin(), students.end(), [&](const auto& a, const auto& b) { return key(a) < key(b); });

这种方法将比较逻辑集中到key函数中,使主排序逻辑更加清晰。当排序规则需要频繁修改时尤为实用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 11:13:20

LPC435x异构双核MCU实战:从架构解析到工业网关应用

1. 项目概述&#xff1a;为什么选择LPC435x系列双核MCU&#xff1f; 在嵌入式开发领域&#xff0c;选型往往是项目成败的第一步。面对市面上琳琅满目的微控制器&#xff0c;是选择单核的简单方案&#xff0c;还是拥抱多核的复杂架构&#xff1f;这个问题在我接手一个工业网关项…

作者头像 李华