C++ 数组排序

想要把数组里的所有元素按大小顺序排列整齐,我们并不需要每次都从头手写复杂的排序逻辑,直接调用 C++ 标准库提供的 std::sort() 函数就能轻松完成。

在实际开发中,对一维数组进行排序主要有两种常见需求:一种是从小到大的 “升序排序”,另一种是从大到小的 “降序排序”。

C++ 数组升序排序

默认情况下,std::sort() 函数会按照从小到大的升序规则对数组元素进行排序,也就是把较小的值排在前面,较大的值排在后面。

语法:

std::sort(std::begin(数组名), std::end(数组名));

说明:

第一次看到这行代码时,很多小伙伴会感到好奇:“既然是对数组排序,为什么不直接把数组名传进去,而要传 std::begin() 和 std::end() 两个参数呢?”

这是因为 std::sort() 支持只对数组中的某一段范围进行排序,因此需要我们明确指定从哪里开始、到哪里结束。当我们想把整个数组从头到尾全部排好序时,只需要按下面的分工配合使用即可:

  • std::sort():C++ 标准库提供的排序函数,使用前需要通过 #include <algorithm> 引入头文件。
  • std::begin(数组名) 和 std::end(数组名):分别用来获取整个数组的 “起始位置” 和 “结束边界”,使用前需要通过 #include <iterator> 引入头文件。

示例 1:数组升序排序

#include <algorithm>    // 提供 std::sort()
#include <iostream>
#include <iterator>     // 提供 std::begin()、std::end()

int main() {
    int arr[] = {50, 20, 80, 10, 60};

    // 对整个数组进行升序排序
    std::sort(std::begin(arr), std::end(arr));

    for (int num : arr) {
        std::cout << num << ' ';
    }
    return 0;
}

运行结果如下。

10 20 50 60 80

分析:

在这个例子中,我们调用 std::sort() 函数对整型数组 arr 进行默认升序排序。执行后,原数组中的 5 个整数会直接按从小到大的顺序重新排列为 10、20、50、60、80,接着我们通过范围 for 循环把排好序的元素依次打印出来。

需要注意一点:std::sort() 是直接修改原数组中元素的排列顺序,而不是创建一个新的数组。除了整型数组之外,它同样支持对浮点数数组(double)或字符数组(char)排序,其中字符会按照 ASCII 码从小到大排列,比如 'a' 排在 'b' 前面。

std::begin() 与数组名加长度写法

在阅读一些早期 C++ 教材或算法竞赛代码时,你可能会看到像 std::sort(arr, arr + 5) 或 std::sort(arr, arr + len) 这样不写 std::begin() 的排序写法。

其实,这里的 arr 代表数组的起始位置,arr + len 代表最后一个元素往后一格的结束边界。由于 std::sort() 的排序范围 “包含起点、不包含终点”,这种写法与传入 std::begin(arr) 和 std::end(arr) 的效果完全等价。

不过在日常开发中对整个数组排序时,我们更推荐使用 std::begin() 和 std::end()。这样不用自己计算并传入元素个数,写起来更直观,也不容易填错长度。

C++ 数组降序排序

如果我们希望把数组按照从大到小的降序顺序排列,比如制作成绩排行榜时把最高分排在最前面,只需要给 std::sort() 传入第 3 个参数 std::greater<>() 即可。

语法:

std::sort(std::begin(数组名), std::end(数组名), std::greater<>());

说明:

在使用 std::greater<>() 之前,我们需要先通过 #include <functional> 引入头文件。从英文意思来看,greater 就是 “更大” 的意思,用来告诉 std::sort() 把较大的元素排在前面。

初学的小伙伴看到 std::greater<>() 时,可能会对中间的尖括号 <> 感到陌生。它涉及后面章节才会学习的模板语法,现阶段不用深究底层原理,直接把它当作固定的 “降序规则” 参数使用即可。

另外,尖括号里也可以写出具体的元素类型,比如写成 std::greater<int>(),两种写法的效果完全相同。写代码时大家要特别留意末尾有一对空的小括号 (),不要漏掉:

// 正确方式
std::sort(std::begin(arr), std::end(arr), std::greater<>());

// 错误方式
std::sort(std::begin(arr), std::end(arr), std::greater<>);

示例 2:数组降序排序

#include <algorithm>     // 提供 std::sort()
#include <functional>    // 提供 std::greater<>()
#include <iostream>
#include <iterator>      // 提供 std::begin()、std::end()

int main() {
    int arr[] = {50, 20, 80, 10, 60};

    // 对整个数组进行降序排序
    std::sort(std::begin(arr), std::end(arr), std::greater<>());

    for (int num : arr) {
        std::cout << num << ' ';
    }
    return 0;
}

运行结果如下。

80 60 50 20 10

分析:

加上第 3 个参数 std::greater<>() 之后,数组 arr 中的 5 个元素就按照从大到小的顺序重新排列成了 80、60、50、20、10。

我们把升序排序和降序排序的写法放在一起对比一下,区别就一目了然了:

// 升序排序
std::sort(std::begin(arr), std::end(arr));

// 降序排序
std::sort(std::begin(arr), std::end(arr), std::greater<>());

数组排序的常见应用

在实际开发中,将数组排好序之后,很多原本需要写循环去逐个比较的操作就会变得简单很多。比如想同时找出数组中的最小值和最大值,我们只需要先对数组做一次升序排序,排好序后的第 1 个元素就是最小值,最后一个元素就是最大值。

示例 3:获取最小值与最大值

#include <algorithm>
#include <iostream>
#include <iterator>

int main() {
    double scores[] = {85.5, 92.0, 76.5, 98.5, 88.0};
    int len = std::size(scores);

    // 先按从小到大升序排序
    std::sort(std::begin(scores), std::end(scores));

    std::cout << "最低分:" << scores[0] << '\n';
    std::cout << "最高分:" << scores[len - 1];
    return 0;
}

运行结果如下。

最低分:76.5
最高分:98.5

分析:

调用 std::sort() 对浮点数数组 scores 进行升序排序后,数组元素依次变为 76.5、85.5、88.0、92.0、98.5。

结合 std::size() 函数获取数组长度 len 之后,排在最前面的 scores[0] 就是最低分 76.5,排在最后面的 scores[len - 1] 就是最高分 98.5。

不过大家在实际开发时也要注意:std::sort() 会直接改变原数组的元素顺序。如果本来就需要把数据排好序展示出来,顺便取首尾元素作为最值非常省事。但如果要求保留原数组的顺序不变,只是想单纯找出最大值或最小值,还是使用一层循环逐个比较更合适。

常见问题

1. 学校作业或考试要求自己手写排序过程,不能直接调用 std::sort() 怎么办?

在日常项目开发中,我们优先使用标准库的 std::sort(),它的运行速度快且不容易出错。如果是课程作业或考试要求自己使用双层循环手写排序算法,可以参考后面的冒泡排序实例来学习具体的交换思路。

2. 除了默认的升序和降序,std::sort() 还能按自定义规则排序吗?

可以。比如想按数字的绝对值大小排序,或者对复杂数据进行多条件排序,只需要给 std::sort() 的第 3 个参数传入自定义的比较规则即可,这部分进阶用法在后面的 “C++ sort 排序” 一节中会详细介绍。

上一篇:

下一篇:

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号