想要把数组里的所有元素按大小顺序排列整齐,我们并不需要每次都从头手写复杂的排序逻辑,直接调用 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 排序” 一节中会详细介绍。
