C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++中的sort与自定义排序

C++中的sort与自定义排序详解

作者:oymaster

std::sort是C++模板函数,采用内省排序(混合快速、堆、插入排序)动态优化性能,确保O(nlogn)效率与鲁棒性,通过比较器、Lambda或重载运算符实现自定义排序逻辑

基本使用与原理

std::sort 是一个模板函数,常见签名如下:

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

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

核心算法:内省排序(Introsort)

C++ 标准未强制指定 std::sort 的实现算法,但大多数现代标准库(如 libstdc++、libc++)采用 内省排序(Introsort)

Introsort 由 David Musser 于 1997 年提出,是一种混合排序算法,结合了快速排序(Quicksort)、堆排序(Heapsort)和插入排序(Insertion Sort)的优点,以兼顾效率和鲁棒性。

1. 快速排序

快速排序是 Introsort 的主要算法,步骤如下:

特点

实现细节

2. 堆排序

当快速排序的递归深度超过阈值(通常为 2 * log n),Introsort 切换到堆排序,以避免快速排序的最坏情况。

步骤

特点

实现细节

3. 插入排序

当子区间大小较小时(通常 < 16 或 32 个元素,具体阈值依实现而定),Introsort 切换到插入排序。

步骤

特点

实现细节

原因:

自定义排序

1. 函数指针

定义一个独立的比较函数,签名需为bool(T, T)

bool compare(int a, int b) {
    return a > b; // 降序排序
}

std::vector<int> vec = {5, 2, 9, 1, 5};
std::sort(vec.begin(), vec.end(), compare); // 结果为 {9, 5, 5, 2, 1}

2. 静态成员函数

在类中定义静态比较函数,避免依赖对象实例:

class Sorter {
public:
    static bool compare(int a, int b) {
        return a > b; // 降序排序
    }
};

std::vector<int> vec = {5, 2, 9, 1, 5};
std::sort(vec.begin(), vec.end(), Sorter::compare);

注意:非静态成员函数因隐含this指针,签名不匹配std::sort的要求,因此无法直接使用。

3. 使用函数对象

通过定义一个类并重载operator(),可以在比较器中存储状态:

class Comparator {
    int threshold;
public:
    Comparator(int t) : threshold(t) {}
    bool operator()(int a, int b) const {
        return a > threshold && a < b; // 仅对大于threshold的元素降序排序
    }
};

std::vector<int> vec = {5, 2, 9, 1, 5};
std::sort(vec.begin(), vec.end(), Comparator(3));

4. 使用Lambda表达式(C++11及以上)

Lambda表达式提供了一种简洁的方式定义比较器,并可捕获外部变量:

int threshold = 3;
std::vector<int> vec = {5, 2, 9, 1, 5};
std::sort(vec.begin(), vec.end(), [threshold](int a, int b) {
    return a > threshold && a < b;
});

5.使用std::function

C++11引入的std::function可以包装任何可调用对象(包括函数指针、Lambda、函数对象等),提供更灵活的方式:

#include <functional>
std::function<bool(int, int)> comp = [](int a, int b) {
    return a > b; // 降序排序
};

std::vector<int> vec = {5, 2, 9, 1, 5};
std::sort(vec.begin(), vec.end(), comp);

适用场景:当需要在运行时动态选择比较器时,std::function非常有用,但会引入少量性能开销。

6.使用标准比较器(如std::greater、std::less)

C++标准库提供了预定义的比较器(如<functional>中的std::greaterstd::less),可直接用于简单排序需求:

#include <functional>
std::vector<int> vec = {5, 2, 9, 1, 5};
std::sort(vec.begin(), vec.end(), std::greater<int>()); // 降序排序
std::sort(vec.begin(), vec.end(), std::less<int>());   // 升序排序

优点:无需手动定义比较器,代码简洁,适合常见升序或降序需求。

7.重载operator<

对于自定义结构体或类,可以通过重载operator<来定义默认排序规则,省去显式比较器:

struct Person {
    std::string name;
    int age;
    bool operator<(const Person& other) const {
        return age < other.age; // 按年龄升序
    }
};

std::vector<Person> people = {{"Alice", 25}, {"Bob", 30}, {"Charlie", 20}};
std::sort(people.begin(), people.end()); // 使用operator<,按年龄升序

适用场景:当类型有自然的排序规则且不需要多种排序方式时,重载operator<是最简洁的方案。

自定义结构体或类的排序

当排序对象是自定义结构体或类时,可以结合上述方法。

例如,使用Lambda:

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

// 按名字字典序排序
std::sort(people.begin(), people.end(), [](const Person& a, const Person& b) {
    return a.name < b.name;
});

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文