nth_element能找第k大是因为它将升序排列后索引为size-k的元素置于指定位置,左侧≤它、右侧≥它;找第k大需传arr.begin()+size-k,而非begin+k。

nth_element 为什么能找第K大,而不是直接叫 find_kth_largest
nth_element 的设计目标是“把第 n 个位置(0-based)放成它在完全排序后该在的值”,不保证前后有序,只保证左侧 ≤ 它、右侧 ≥ 它(默认升序)。所以找“第K大”,本质是找“升序排列后索引为 size - k 的元素”。比如数组有10个数,第1大就是升序后索引9的值,第3大就是索引7的值。
常见错误是传错位置:写成 nth_element(begin, begin + k, end),结果拿到的是第K小——尤其当题目明确说“第K大”时,这坑踩得最多。
- 要找第K大 → 目标位置是
begin + (arr.size() - k) - 确保
k合法:1 ≤k≤arr.size(),否则越界或行为未定义 - 如果
k是从1开始计数(题目常见),别手抖写成k-1升序索引——那是第K小
怎么写才不崩:迭代器、比较函数、原地修改
nth_element 必须作用于可随机访问的容器(vector、array、裸指针),且会原地重排部分元素。它不返回值,结果就存在目标迭代器指向的位置。
升序找第K大,最简写法:
vector<int> arr = {3, 2, 1, 5, 6, 4};
int k = 2;
nth_element(arr.begin(), arr.begin() + arr.size() - k, arr.end());
// 此时 arr[arr.size() - k] 就是第k大的数
</int>
如果想更直观(避免每次算 size - k),用自定义比较器降序处理:
- 传
greater<int>()</int>,然后直接取arr.begin() + k - 1 - 注意:降序下第1大在索引0,第2大在索引1,所以是
k - 1 - 但降序版对
nth_element性能无实质提升,只是语义清晰些
和 partial_sort、sort 比,差在哪
nth_element 平均时间复杂度是 O(n),比 sort 的 O(n log n) 快,也比 partial_sort(O(n log k))更适合纯找第K个的场景。但它不保证前K个有序——如果你后续还要取前K大并排序,那不如直接 partial_sort。
容易被忽略的点:
- 它不保证“前K个就是最大的K个”——只保证目标位正确,左边元素 ≤ 它,但未必是最大的K−1个(可能混着小的)
- 多线程不安全:不能并发调用同一容器上的
nth_element - 对
list或forward_list无法使用——没有随机访问迭代器
边界情况实测建议
实际编码时,这几个 case 最容易出错:
-
k == 1:应得最大值,检查是否真拿到*max_element结果 -
k == arr.size():应得最小值,确认没越界访问 - 重复元素:如
{2,2,2,2}找第2大,结果仍是2,没问题——nth_element对重复值行为确定 - 空容器或
k越界:必须提前判断,否则触发 undefined behavior,不是抛异常
真正难的不是调用语法,而是想清楚“第K大”在当前排序语义下对应哪个内存位置;算错一位,结果就完全不对,而且还不报错。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











