C++ 标准库排序算法 std::sort 使用详解

  • C++ 中确实存在很多经典排序算法(快速排序、归并排序、堆排序、希尔排序等)。

  • 每种排序算法都有其优势和适用场景(比如归并适合链表,桶排序适合范围已知的整数,堆排序适合实时取最大/最小值)。

  • C++ 标准库中的 std::sort 内部实现是一个 混合排序算法 ,主要基于 快速排序(QuickSort) ,在某些情况下会退化为堆排序或插入排序,所以它的时间复杂度一般为 O(N log N) 。它不仅能对内置类型(如 intdouble)排序,还能自定义比较规则,甚至结合 C++20 的并行执行策略实现更高效的排序。

本文将从最基础的用法开始,逐步介绍 std::sort 的高级特性。


C++ std::sort 参数详解

在 C++ 中,std::sort 是最常用的排序函数之一。它定义在 <algorithm> 头文件中,能对容器(如 vectorarray)或数组中的元素进行快速排序。

函数原型(常见用法):

cpp 复制代码
template <class RandomIt>
void sort(RandomIt first, RandomIt last);

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

可以看到,std::sort 一共有两个版本:

  • 两个参数:默认按升序排序。

    • 排序的对象范围由两个迭代器决定:

    • first → 排序起点

    • last → 排序终点的"下一个位置"

    • 注意是 左闭右开区间 [first, last) ,包含 first 指向的元素,但不包含 last 指向的元素。

  • 三个参数:用户可以指定排序规则。

    • 默认情况下,std::sort 使用 < 作为比较规则(升序)。

      但你可以传入一个比较函数(或函数对象、Lambda 表达式),来自定义排序规则。

1. 基础用法:升序排序

如果不传入自定义比较函数,std::sort 默认会使用 小于运算符 < 进行比较,从而将元素按升序排列。

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> values = { 3, 5, 1, 4, 2 };

    // 默认升序排序
    std::sort(values.begin(), values.end());

    for (int v : values)
        std::cout << v << " ";
    // 输出:1 2 3 4 5
}

2. 降序排序

如果想要从大到小排列,可以传入标准库提供的 std::greater<> 比较器:

cpp 复制代码
#include <functional> // std::greater

std::sort(values.begin(), values.end(), std::greater<int>());

// 输出:5 4 3 2 1

3. 自定义比较规则

有时候我们需要更复杂的排序逻辑,这时可以传入一个 自定义比较函数(函数指针、函数对象或 Lambda 表达式)。

例如,让数字 1 永远排在最后:

cpp 复制代码
std::sort(values.begin(), values.end(), [](int a, int b) {
    if (a == 1) return false; // a==1 时排在 b 之后
    if (b == 1) return true;  // b==1 时排在 a 之前
    return a < b;             // 其他情况正常升序
});

// 输出:2 3 4 5 1

注意:比较函数必须返回 bool,且要满足 严格弱序关系(Strict Weak Ordering),否则结果可能是未定义的。


4. std::sort 的函数签名

标准库中 std::sort 的定义大致如下:

cpp 复制代码
// 默认比较:使用 operator<
template<class RandomIt>
void sort(RandomIt first, RandomIt last);

// 自定义比较器
template<class RandomIt, class Compare>
void sort(RandomIt first, RandomIt last, Compare comp);

// C++17 起:并行排序(可指定执行策略)
template<class ExecutionPolicy, class RandomIt>
void sort(ExecutionPolicy&& policy, RandomIt first, RandomIt last);

template<class ExecutionPolicy, class RandomIt, class Compare>
void sort(ExecutionPolicy&& policy, RandomIt first, RandomIt last, Compare comp);

参数说明:

  • first, last

    迭代器范围 [first, last),要排序的区间。

  • comp

    自定义比较函数(bool comp(const T& a, const T& b))。

  • policy(C++17 起)

    执行策略,例如 std::execution::seq(顺序执行)、std::execution::par(并行执行)。


5. 使用要求

为了让 std::sort 工作正常,需要满足以下条件:

  1. 迭代器必须是 随机访问迭代器 (Random Access Iterator),例如 std::vectorstd::array、原生数组。

    std::list 不行,因为它只支持双向迭代器。)

  2. 元素类型必须:

    • 可交换(Swappable)

    • 可移动构造(MoveConstructible)

    • 可移动赋值(MoveAssignable)

  3. 自定义比较器必须满足 Compare 要求(即符合严格弱序)。


6. 时间复杂度

  • 默认比较或自定义比较:
    O(N log N) 次比较(这里 N = last - first)。

  • 实现一般基于 快速排序 + 堆排序 + 插入排序 的混合策略。


7. 示例:排序结构体

std::sort 常用于排序对象数组。我们可以自定义排序规则:

cpp 复制代码
#include <string>

struct Person {
    std::string name;
    int age;
};

int main() {
    std::vector<Person> people = {
        {"Alice", 25},
        {"Bob", 30},
        {"Charlie", 20}
    };

    // 按年龄升序
    std::sort(people.begin(), people.end(), [](const Person& a, const Person& b) {
        return a.age < b.age;
    });

    for (const auto& p : people)
        std::cout << p.name << " " << p.age << "\n";
    // 输出:
    // Charlie 20
    // Alice 25
    // Bob 30
}

8. 总结

  • std::sort 是 C++ 排序的首选,效率高,接口灵活。

  • 默认是升序排序,可以用 std::greater<> 或自定义比较器实现降序或更复杂的规则。

  • 内部复杂度是 O(N log N),但实现经过高度优化。

  • 迭代器必须支持随机访问,类型必须可移动、可交换。

  • C++17 之后可以使用执行策略(并行排序)。


建议:

  • 简单场景直接用默认排序;

  • 如果有特殊规则,写一个清晰的比较函数;

  • 不要忘了比较函数要符合 严格弱序,否则可能出现奇怪的排序结果。

相关推荐
两只程序猿4 小时前
数据可视化 | Violin Plot小提琴图Python实现 数据分布密度可视化科研图表
开发语言·python·信息可视化
野生技术架构师4 小时前
1000 道 Java 架构师岗面试题
java·开发语言
湫兮之风4 小时前
C++: Lambda表达式详解(从入门到深入)
开发语言·c++
奔跑吧邓邓子4 小时前
【C++实战(54)】C++11新特性实战:解锁原子操作与异步编程的奥秘
c++·实战·c++11新特性·原子操作·异步编程
Porunarufu4 小时前
JAVA·顺序逻辑控制
java·开发语言
Sylvia-girl4 小时前
C语言中经常使用的函数
c语言·开发语言
~无忧花开~5 小时前
JavaScript学习笔记(十五):ES6模板字符串使用指南
开发语言·前端·javascript·vue.js·学习·es6·js
周杰伦fans5 小时前
C# 23种设计模式详解与示例
开发语言·设计模式·c#
Mr_WangAndy5 小时前
C++设计模式_结构型模式_适配器模式Adapter
c++·设计模式·适配器模式·c++设计模式