news 2026/4/24 14:52:35

别再只会用sort了!C++ vector自定义排序的三种实战写法(含pair和二维vector)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
别再只会用sort了!C++ vector自定义排序的三种实战写法(含pair和二维vector)

解锁C++ vector排序的进阶姿势:三种自定义排序方法深度解析

在LeetCode刷题和数据处理实战中,我们经常需要对复杂数据结构进行排序。vector作为C++中最常用的容器之一,其排序操作尤为关键。但当你面对vector<pair<int,int>>vector<vector<int>>时,是否感到无从下手?本文将带你突破基础sort的限制,掌握三种实战中最高效的自定义排序方法。

1. 为什么需要自定义排序?

标准库中的sort函数默认采用升序排列,这对于简单数据类型足够使用。但在实际开发中,我们经常遇到更复杂的排序需求:

  • 多维度排序(先按第一元素降序,再按第二元素升序)
  • 自定义对象排序
  • 特定业务逻辑排序(如按字符串长度、按奇偶性等)
// 默认排序示例 vector<int> nums = {3,1,4,1,5,9,2,6}; sort(nums.begin(), nums.end()); // 结果:1,1,2,3,4,5,6,9

当数据结构变得复杂时,简单的升序/降序就无法满足需求了。下面我们来看三种实战中最常用的自定义排序方法。

2. 外部cmp函数:结构化排序的经典方案

外部比较函数是最传统也最清晰的自定义排序方式,特别适合复杂排序规则的场景。

2.1 基本用法

static bool cmp(const vector<int>& a, const vector<int>& b) { if(a[0] == b[0]) return a[1] < b[1]; // 第二元素升序 return a[0] > b[0]; // 第一元素降序 } vector<vector<int>> data = {{1,2},{1,1},{2,3},{0,4}}; sort(data.begin(), data.end(), cmp); // 结果:{{2,3},{1,1},{1,2},{0,4}}

2.2 LeetCode中的特殊注意事项

在类内定义cmp函数时,必须声明为static

class Solution { public: static bool cmp(const pair<int,int>& a, const pair<int,int>& b) { return a.second < b.second; } vector<int> topKFrequent(vector<int>& nums, int k) { // ...使用cmp进行排序 } };

注意:static修饰符是必须的,因为非静态成员函数有隐含的this指针参数,与sort函数要求的比较函数签名不匹配。

2.3 性能优化技巧

使用引用避免不必要的拷贝:

static bool cmp(const vector<int>& a, const vector<int>& b) { // 使用const &避免拷贝 }

3. Lambda表达式:灵活简洁的现代C++方案

C++11引入的Lambda表达式为排序提供了更灵活的解决方案,特别适合一次性使用的排序逻辑。

3.1 基本语法

vector<pair<int,int>> points = {{1,2},{1,1},{2,3},{0,4}}; sort(points.begin(), points.end(), [](const auto& a, const auto& b) { return a.first + a.second > b.first + b.second; // 按元素和降序 });

3.2 捕获列表的妙用

Lambda可以捕获上下文变量,实现更动态的排序:

int base = 5; sort(points.begin(), points.end(), [base](const auto& a, const auto& b) { return abs(a.first - base) < abs(b.first - base); // 按与base的距离升序 });

3.3 auto类型推导

使用auto让代码更简洁:

sort(points.begin(), points.end(), [](const auto& a, const auto& b) { // 自动推导a,b的类型 });

4. 函数对象:复用性高的专业方案

对于常用的排序规则,可以封装为函数对象,提高代码复用性。

4.1 使用标准库函数对象

vector<int> nums = {3,1,4,1,5,9}; sort(nums.begin(), nums.end(), greater<int>()); // 降序排列

4.2 自定义函数对象

struct CompareSecond { bool operator()(const pair<int,int>& a, const pair<int,int>& b) const { return a.second < b.second; } }; vector<pair<int,int>> items = {{1,4},{2,3},{3,2},{4,1}}; sort(items.begin(), items.end(), CompareSecond());

4.3 带状态的函数对象

函数对象可以保存状态,实现更复杂的排序逻辑:

class CustomComparator { int mode; public: CustomComparator(int m) : mode(m) {} bool operator()(const vector<int>& a, const vector<int>& b) const { if(mode == 1) return a[0] < b[0]; else return a[1] < b[1]; } }; vector<vector<int>> data = {{1,4},{2,3},{3,2},{4,1}}; sort(data.begin(), data.end(), CustomComparator(2)); // 按第二列排序

5. 三种方法对比与选型指南

方法优点缺点适用场景
外部cmp函数结构清晰,可复用需要单独定义,类内需static复杂排序规则,多处复用
Lambda表达式灵活简洁,可捕获变量一次性使用,复用性差简单临时排序,需要上下文变量
函数对象可复用,可保存状态代码量稍大需要配置参数的排序,专业库开发

在实际项目中,我通常会根据以下原则选择:

  1. 简单临时排序:优先使用Lambda,代码紧凑
  2. 复杂业务排序:使用外部cmp函数,逻辑清晰
  3. 需要配置的排序:使用函数对象,灵活性高
  4. 类内实现:注意cmp必须是static

6. 实战中的常见陷阱与解决方案

6.1 严格弱序问题

比较函数必须满足严格弱序,否则会导致未定义行为:

// 错误示例:不满足严格弱序 bool cmp(int a, int b) { return a <= b; // 错误!应该用< }

6.2 类成员函数排序

在类内排序成员变量时,Lambda可能是更好的选择:

class Processor { vector<int> data; public: void sortData() { sort(data.begin(), data.end(), [this](int a, int b) { return this->someMethod(a) < this->someMethod(b); }); } };

6.3 性能优化

对于大型数据集,比较函数的性能变得关键:

  • 尽量使用引用传递参数
  • 避免在比较函数中进行复杂计算
  • 考虑预先计算好比较键值
// 预先计算键值 vector<pair<int, vector<int>>> temp; for(const auto& v : data) { temp.emplace_back(computeKey(v), v); } sort(temp.begin(), temp.end());

7. 高级应用:多维度排序策略

对于需要按多个字段排序的场景,可以组合多种技术:

vector<tuple<int,int,string>> records = { {1, 2, "apple"}, {1, 1, "banana"}, {2, 1, "orange"} }; // 按第一字段升序,第二字段降序,第三字段长度升序 sort(records.begin(), records.end(), [](const auto& a, const auto& b) { if(get<0>(a) != get<0>(b)) return get<0>(a) < get<0>(b); if(get<1>(a) != get<1>(b)) return get<1>(a) > get<1>(b); return get<2>(a).size() < get<2>(b).size(); });

8. 实际案例分析:LeetCode题目应用

以LeetCode 452题(用最少数量的箭引爆气球)为例,展示自定义排序的实际价值:

class Solution { public: int findMinArrowShots(vector<vector<int>>& points) { if(points.empty()) return 0; // 按结束位置排序 sort(points.begin(), points.end(), [](const auto& a, const auto& b) { return a[1] < b[1]; }); int arrows = 1; int end = points[0][1]; for(int i = 1; i < points.size(); ++i) { if(points[i][0] > end) { arrows++; end = points[i][1]; } } return arrows; } };

在这个解法中,自定义排序是算法的关键,它确保了我们可以贪心地选择射击位置。

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

Z-Image本地化AI工具链:LM系列权重清洗→注入→生成→对比一体化

Z-Image本地化AI工具链&#xff1a;LM系列权重清洗→注入→生成→对比一体化 1. 工具概述 Z-Image本地化AI工具链是专为LM系列自定义权重设计的全流程测试解决方案。基于阿里云通义Z-Image底座开发&#xff0c;这套工具链实现了从权重清洗、注入到生成、对比的一体化操作&…

作者头像 李华
网站建设 2026/4/24 14:51:42

解决CKEditor5全屏退出后分页错乱:3步完美修复方案

解决CKEditor5全屏退出后分页错乱&#xff1a;3步完美修复方案 【免费下载链接】ckeditor5 Powerful rich text editor framework with a modular architecture, modern integrations, and features like collaborative editing. 项目地址: https://gitcode.com/GitHub_Trend…

作者头像 李华
网站建设 2026/4/24 14:50:45

暗黑破坏神2存档修改器终极指南:5分钟学会游戏存档编辑

暗黑破坏神2存档修改器终极指南&#xff1a;5分钟学会游戏存档编辑 【免费下载链接】d2s-editor 项目地址: https://gitcode.com/gh_mirrors/d2/d2s-editor 还在为暗黑破坏神2中反复刷装备而烦恼吗&#xff1f;想快速体验不同职业的build却不想从头练级&#xff1f;d2s…

作者头像 李华
网站建设 2026/4/24 14:50:42

终极指南:5步用Python的Mesa框架构建智能体仿真模型

终极指南&#xff1a;5步用Python的Mesa框架构建智能体仿真模型 【免费下载链接】mesa Mesa is an open-source Python library for agent-based modeling, ideal for simulating complex systems and exploring emergent behaviors. 项目地址: https://gitcode.com/gh_mirro…

作者头像 李华
网站建设 2026/4/24 14:49:53

Qwen3-4B-Thinking开发者工具链:VS Code插件+Jupyter内核支持

Qwen3-4B-Thinking开发者工具链&#xff1a;VS Code插件Jupyter内核支持 1. 模型概述 Qwen3-4B-Thinking-2507-Gemini-2.5-Flash-Distill是基于通义千问Qwen3-4B官方模型开发的高效推理版本。该模型采用4B参数稠密架构&#xff0c;具备原生256K tokens上下文窗口&#xff0c;…

作者头像 李华