跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

用好 std::sort:自定义排序与常见陷阱

C++ 标准库 sort 函数支持默认升序和自定义比较,底层采用 Introsort 保证 O(n log n) 复杂度。自定义比较需严格遵循严格弱序,否则会导致未定义行为。常见陷阱包括比较函数误用 <= 或忽略运算符重载。掌握这些后可灵活用于数据处理、算法题和实际项目排序。

日志猎手发布于 2026/6/25更新于 2026/8/2318 浏览

C++ 标准库的 sort() 在 <algorithm> 头文件中,只要容器支持随机访问迭代器(如 vector、array、deque)就能用。它最常用的场景是直接对元素做升序排列,但实际工作中很少只满足于默认行为——降序、按成员变量排序、甚至非全序的比较才是日常。

函数原型

sort() 有两个重载:

template<class RandomAccessIterator>
void sort (RandomAccessIterator first, RandomAccessIterator last);

template<class RandomAccessIterator, class Compare>
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

first 和 last 构成左闭右开区间 [first, last)。comp 是可调用对象,当 comp(a, b) 返回 true 时,a 排在 b 前面。使用前记得包含 <algorithm>,函数位于 std 命名空间。

默认升序

对整数数组或容器,默认就是从小到大的升序,底层用 operator< 比较。

int arr[] = {3, 1, 4, 1, 5};
sort(arr, arr + 5);
// arr 变成 1 1 3 4 5

vector 同理:

vector<int> v = {3, 1, 4, 1, 5};
sort(v.begin(), v.end());
// v 变成 1 1 3 4 5

自定义比较:降序与更多玩法

想让大的在前面,最简单的办法是传一个 greater<int>() 函数对象(需要 <functional>):

#include <functional>
sort(v.begin(), v.end(), greater<int>());

当然可以手写比较函数。比如对学生按成绩降序:

struct Student {
    string name;
    int score;
};

bool byScoreDesc(const Student& a, const Student& b) {
    return a.score > b.score;
}

vector<Student> students = {{"Alice", 85}, {"Bob", 90}};
sort(students.begin(), students.end(), byScoreDesc);

任何能接收两个元素并返回 bool 的可调用对象都行,包括 lambda:

sort(students.begin(), students.end(),
     [](const Student& a, const Student& b) { return a.score > b.score; });

复杂规则也能轻松实现,比如按个位数大小排序:

sort(v.begin(), v.end(), [](int a, int b) { return (a % 10) < (b % 10); });

它到底怎么排的

sort() 的实现通常是 Introsort(内省排序)。它从快速排序开始,但当递归深度超过 log₂(n) 的阈值时会切换成堆排序,避免快排退化到 O(n²);当区间长度小到一定规模(比如 16)时又改用插入排序,利用小数据量下常数开销低的优势。这种混血策略让平均和最坏时间复杂度都稳稳停在 O(n log n)。

最容易踩的坑:比较函数

大部分 sort() 导致的奇奇怪怪崩溃,根因都在比较函数没有满足严格弱序。

严格弱序要求:

  • 如果 comp(a,b) 为真,则 comp(b,a) 必须为假(不对称)。
  • 传递性:若 comp(a,b) 和 comp(b,c) 都为真,则 comp(a,c) 也必须为真。
  • 等价关系:!comp(a,b) && !comp(b,a) 被视为等价(不要求 ==)。

常见错误是用了 <= 或 >=:

// 危险!不满足严格弱序
bool bad(int a, int b) {
    return a <= b;
}

这种比较会让 a 在跟自身或等值元素比较时返回 true,破坏不对称性,可能让元素越界、死循环甚至段错误。正确写法是用 < 或 >,不要带等号。

另一个坑是自定义类型没有重载 operator<,而你又没传比较函数。这时候编译不过,解决方法是给个 lambda 或者重载 <。

适用场景

  • 数据处理:想找出销量前几名的商品,按数量降序排一下就出来了。
  • 算法题:求第 K 大元素,排序后直接取 v[k-1](降序)是最快的实现(虽然 nth_element 更合适,但 sort 够简单)。
  • 项目里:成绩排名、日志按时间戳排序,都是基本操作。

sort() 本身很皮实,用好它的关键是理解那个比较函数——严格弱序不能妥协,剩下的就是效率上的加分项了。

目录

  1. 函数原型
  2. 默认升序
  3. 自定义比较:降序与更多玩法
  4. 它到底怎么排的
  5. 最容易踩的坑:比较函数
  6. 适用场景
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Git 分支管理实战指南
  • GitHub Pages 制作个人主页教程
  • 云服务器 MySQL 8.0 安装与远程连接配置
  • HDFS 读写机制深度解析:分布式存储核心原理
  • Python 异步编程实战:构建高性能网络应用
  • ClawdBot 生产环境实战:Webhook 对接企微/钉钉实现跨平台同步
  • 人形全身 VLA 模型Ψ0:基于人类视频预训练与 MM-DiT 后训练方案
  • Open WebUI 本地部署指南:基于 Ollama 的 AI 对话界面搭建
  • OnlyOffice 私有化部署与 Spring Boot 整合实战教程
  • AIGC 镜头控制教程:Next Scene Qwen Image LoRA 实现视角变换
  • C++ 轻量级搜索引擎实战:构造正/倒排索引
  • 2026 年 AI 编程助手组合使用心得
  • 医疗 AI 可信革命全栈实现:向量索引与贝叶斯网络
  • 微博登录流程逆向分析与加密参数实现
  • 前端开发:如何使用浏览器开发者工具查看接口请求与响应
  • Clawdbot 飞书机器人配置与实战指南
  • Python 3.10 的 6 个核心新特性详解
  • 提升 AI 模型能力的 10 个必备技能指南
  • 数据结构:八种常见排序算法详解
  • JavaSE 核心知识点全解:从基础语法到多线程实战

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online