CC++ & Algorithm

sort排序函数

中等14
语言版本:C++
概述:sort函数就像一个自动整理书架的工具,只要告诉它要整理哪些书,它就能按顺序排好。

一键排序:C++ 的 sort 函数,像魔法一样整理你的数据

你是不是经常为考试成绩排名、零花钱花费记录或者一堆乱糟糟的数字发愁?要是有一个魔法,只要说“从低到高排好”,所有数字就自动站好队,那该多省事!
C++ 的 sort 函数就是这样的魔法——它能在瞬间把数组、vector 等容器里的数据排好顺序。不管你是想从小到大(升序)还是从大到小(降序),它都能轻松搞定。

要使用 sort,必须先请它出场:在代码开头加上 #include <algorithm>。这就像书架上放了一个“整理工具箱”,sort 就在里面。

基本用法:告诉它“从哪里排到哪”

sort 函数的调用方法是:

sort(起始地址, 结束地址);

这里有个特别重要的规律:结束地址是“最后一个元素的下一个位置”,也就是不包含这个位置。
举个例子,如果你的书架有 10 本书,编号 09,你想整理前 5 本(编号 04),那么起始地址是第 0 本(书架的起点),结束地址是编号 5 的那本书的位置(虽然那里并没有书)。
在 C++ 数组里,这个地址通常写作 arr + n,其中 n 是要排序的元素个数。
对于 vector 容器,不需要自己算地址,直接用 v.begin() 表示起点,v.end() 表示终点(最后一个元素的下一个位置)。

下面的例子会让你更清楚。

例1:给零花钱排个序(从小到大)

假设你记录了一周每天的零花钱支出:5 元、2 元、8 元、1 元、9 元。用 sort 可以按金额从小到大排序。

#include <iostream>
#include <algorithm>   // sort 的家
using namespace std;

int main() {
    int arr[] = {5, 2, 8, 1, 9};
    int n = 5;

    // 对整个数组排序,arr 是起始地址,arr+n 是不包含的结束地址
    sort(arr, arr + n);

    cout << "排序后的零花钱:";
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;  // 输出:1 2 5 8 9

    return 0;
}

小提示:这里的 arr + n 指向数组最后一个元素的下一个位置,也就是不存在的第 5 个元素。如果写成 arr + 5,意思就是排从 arr[0]arr[4] 这 5 个元素。

例2:考试分数从高到低排名(降序)

默认 sort 是从小到大(升序),但我们有时想要从大到小(降序),比如看谁分数最高。这时候需要第三个参数——一个“排序规则”。
C++ 已经为你准备好了 greater<int>() 这个工具,意思是“越大的越往前”。

#include <iostream>
#include <vector>
#include <algorithm>   // sort 和 greater 都在这里
using namespace std;

int main() {
    // 存储一次数学考试的成绩
    vector<int> scores = {88, 95, 70, 100, 82};

    // 从大到小排序,greater<int>() 就是“越大越靠前”的规则
    sort(scores.begin(), scores.end(), greater<int>());

    cout << "成绩从高到低:";
    for (int score : scores) {   // C++11 范围for循环,省心又安全
        cout << score << " ";
    }
    cout << endl;  // 输出:100 95 88 82 70

    return 0;
}

如果想从小到大,既可以不写第三个参数,也可以写 less<int>()(表示“越小越靠前”)。不过默认就是 less<int>(),所以平时不写也行。


区间范围:理解“起始”和“结束”

sort 的区间是 左闭右开 的,也就是包括起始元素,但不包括结束元素。这个概念初学者容易搞混,我们仔细看一下:

  • 对数组 int a[10]sort(a, a+5) 排的是 a[0]a[4](共5个元素),a[5] 及之后的不动。
  • 对 vector vsort(v.begin(), v.end()) 排所有元素;如果只想排前3个,可以写 sort(v.begin(), v.begin()+3)
  • 也可以只排中间一段:比如 sort(v.begin()+2, v.begin()+5) 排第3个到第5个元素(索引2,3,4)。

形象记忆:把 begin 当作你手指的起点,end 是你手指停下的地方,但不会碰到那本书。


新手容易犯的错误(快来避坑)

  1. 忘记包含头文件
    #include <algorithm> 没写,编译器会报错:“找不到 sort 函数”。就像做菜没拿锅铲一样。

  2. 结束地址写错了
    对数组 int a[100],如果写 sort(a, a+100) 是对的(排 100 个元素)。
    但初学者可能会写成 sort(a, a+99),那就只排了前 99 个,最后一个没进去。
    或者写成 sort(a, a+101),数组越界,程序可能崩溃。

  3. 对 vector 用指针
    vector 的迭代器不是普通指针,不能用 v 或者 v+5 当作起始地址。一定要用 v.begin()v.end()
    错误示范:sort(v, v+5); 这是不行的。

  4. 降序时忘记加括号
    greater<int>() 是一个函数对象,后面的括号不能省。写成 greater<int> 不带括号是错误的,编译器会以为你在说类型而不是对象。

  5. 自定义类型没有比较规则
    如果 vector 里存的是你自己定义的结构体(比如学生、书籍),sort 不知道按哪个字段排,会报错。这时就需要写自定义比较函数(后面有介绍)。


完整示例:按零食价格排序(升序 + 降序)

下面是一个完整的程序,它创建了一个 vector 存储几种零食的价格,先按从低到高排序,再按从高到低排序,并输出结果。

#include <iostream>
#include <vector>
#include <algorithm>   // 包含 sort 和 greater
using namespace std;

int main() {
    // 零食价格(单位:元)
    vector<int> prices = {3, 7, 1, 10, 5};

    cout << "原始价格:";
    for (int price : prices) {
        cout << price << " ";
    }
    cout << endl;

    // 从小到大排序(默认升序)
    sort(prices.begin(), prices.end());
    cout << "从低到高排序:";
    for (int price : prices) {
        cout << price << " ";
    }
    cout << endl;

    // 从大到小排序(用 greater<int>() 降序)
    sort(prices.begin(), prices.end(), greater<int>());
    cout << "从高到低排序:";
    for (int price : prices) {
        cout << price << " ";
    }
    cout << endl;

    return 0;
}

输出结果

原始价格:3 7 1 10 5 
从低到高排序:1 3 5 7 10 
从高到低排序:10 7 5 3 1 

进阶小挑战:自己定规矩(自定义排序)

有时候排序的规则不是简单的数字大小。比如,你想按数字的个位数排序(不管百位十位),或者按姓名长度,甚至按两个条件排名。这时你可以自己写一个“比较函数”,然后作为第三个参数传给 sort

比较函数的写法是:返回 true 表示第一个参数应该排在第二个参数前面。举个例子,按个位数从小到大排:

// 自定义比较函数:只看个位数
bool cmp_by_last_digit(int a, int b) {
    return (a % 10) < (b % 10);
}

// 使用:sort(arr, arr + n, cmp_by_last_digit);

对于中小学生,知道有这种方法就行。等以后学到结构体,就可以用它来排成绩单、排游戏角色等更复杂的数据。


小练习(自己做做看)

  1. 创建一个 vector,存储你最喜欢的 5 个数字(比如生日、幸运数字等)。
  2. sort 把它们从小到大排序,然后输出。
  3. 改成 greater<int>() 再排序,看看发生了什么变化。

思考:如果 vector 里的数字有重复的,排序后它们会挨在一起吗?试试看!


相关知识点指引

  • stable_sort:跟 sort 类似,但是当两个元素相等时,会保持它们原来的相对顺序(即稳定排序)。如果你在排队后还关心先后次序,可以用它。
  • partial_sort:有时候你只想排出前几名,比如全年级成绩的前 10 名,后面的不用排太细。partial_sort 可以只排好前几名,后面的随便站。
  • 手动排序算法:如果不用 sort,你也可以自己写选择排序、冒泡排序或插入排序。虽然慢一些,但能让你更理解排序的每一步是怎么做的——这也是初学者非常重要的基本功。
  • 自定义比较函数:对于结构体数组或类容器,需要自己编写比较规则,这样 sort 才知道按什么排序。

记住,sort 是目前 C++ 里最方便、最快速的排序工具之一,学好它,以后遇到排序任务就不用发愁啦!

例题精讲

1单选题

使用sort函数对一个int数组a(大小为10)进行升序排序,以下哪项调用是正确的?

Asort(a[0], a[10])
Bsort(a, a+9)
Csort(a, a+10)
Dsort(a+1, a+10)
2判断题

sort函数可以对所有容器类型(如list、vector、deque)进行排序。

3填空题
以下代码希望将数组arr(int类型,大小n)按从大到小排序,请填空:
#include <algorithm>
#include <functional>
using namespace std;
int arr[] = {3, 1, 4, 1, 5, 9};
int n = sizeof(arr)/sizeof(arr[0]);
sort(arr, arr + n, ___);
4单选题

关于sort函数的时间复杂度,以下哪个描述正确?

Asort默认按降序排列
Bsort默认使用operator>进行比较
Csort默认使用operator<进行升序排列
Dsort默认使用less<int>()进行降序排列
5判断题

sort函数要求排序范围必须是连续的,即[first, last)中的元素可以通过迭代器自增逐个访问。