C++ 实现快速选择算法查找第 K 大数值所在位置平均复杂度解析【源码】

大婷吖_7454

大婷吖_7454

2026-05-18

818人浏览

原创

快速选择算法平均时间复杂度为O(n),因其每次partition后仅递归处理含目标的一侧,期望规模减半,总操作量收敛于2n;而快排需递归两侧故为O(n log n),退化情形(如pivot总选极值)下为O(n²)。

c++ 实现快速选择算法查找第 k 大数值所在位置平均复杂度解析【源码】

快速选择算法为什么平均时间复杂度是 O(n)

因为每次划分后,只递归处理包含目标位置的那一侧子数组,期望下一次处理的规模约为上一次的 1/2。数学上可推得总操作数收敛于 2n,即 O(n);这和快排的 O(n log n) 本质区别在于:快排要两边都递归,而快速选择只进一边。

但要注意:这个“平均”依赖于 partition 的基准(pivot)足够随机。若每次选到最小或最大元素作 pivot(比如已排序数组中固定取首/尾),就会退化成 O(n²)。

实操建议:

  • 务必对输入数组做随机打乱,或在 partition 中用 rand() 随机选 pivot 索引,再与末尾交换
  • 避免直接用 arr[0] 或 arr[r] 作为 pivot —— 这是退化的常见源头
  • 小规模子数组(如长度

如何返回第 K 大值的原始索引而非数值本身

快速选择默认返回值,但题目要求“所在位置”,意味着必须保留原始下标信息。不能只对值排序或 partition,得把索引和值绑定传递。

常见错误现象:nth_element 或手写 quickSelect 直接作用于值数组,结果找不到原位置。

正确做法是维护一个索引数组,并按对应值比较:

vector<int> idxs(arr.size());
iota(idxs.begin(), idxs.end(), 0);
nth_element(idxs.begin(), idxs.begin() + k - 1, idxs.end(),
    [&arr](int i, int j) { return arr[i] > arr[j]; });
// 此时 idxs[k-1] 就是第 K 大值在原数组中的下标
</int>

注意:这里用 arr[i] > arr[j] 实现降序比较,对应“第 K 大”;若用升序,则应取 idxs[n - k]。

std::nth_element 能否直接用于找第 K 大位置

可以,但需注意两个关键点:比较器方向、迭代器偏移。

std::nth_element 保证第 n 个位置(从 0 开始)的元素就位,且左侧 ≤ 它、右侧 ≥ 它(默认升序)。要找第 K 大,等价于升序下的第 n - k 小元素。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载

实操建议:

  • 调用形式为 nth_element(begin, begin + n - k, end),不是 begin + k - 1
  • 若坚持用“第 K 大”语义,必须传自定义比较器 greater(),此时目标位置是 begin + k - 1
  • 它不保证其余元素有序,只保证分区性质 —— 所以不能靠它取 top-K 全部索引,除非多次调用或配合额外逻辑

示例(返回第 3 大值的原始下标):

vector<int> arr = {3, 2, 1, 5, 6, 4};
vector<int> idxs = {0,1,2,3,4,5};
nth_element(idxs.begin(), idxs.begin() + 2, idxs.end(),
    [&arr](int i, int j) { return arr[i] > arr[j]; });
// idxs[2] 即所求位置
</int></int>

手写 partition 时最容易踩的边界坑

手写 partition 是理解原理的关键,但 l 判断、swap 时机、循环后 pivot 归位这三处极易出错,导致死循环或结果错位。

典型错误现象:在某些输入下返回错误索引,或程序卡死在 while 循环里。

推荐使用 Lomuto 分区方案(更直观),并严格遵循以下顺序:

  • 随机选 pivot 后与右端交换,统一处理
  • 设 i = l - 1,遍历 j 从 l 到 r - 1
  • 仅当 arr[j] > pivot(求第 K 大)时才执行 i++ 并 swap(arr[i], arr[j])
  • 最后 swap(arr[i+1], arr[r]),返回 i + 1

特别注意:比较条件必须和目标一致 —— 求第 K 大,就要让大的元素往左堆;若写成 就会反向分区,后续递归区间也会全错。

复杂点其实在于:同一套 partition 逻辑,换一个比较方向或目标定义(K 小/K 大),整个索引映射关系就得重算。很多人调试半天才发现是这儿反了。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
c++和c语言的区别有哪些
c++和c语言的区别有哪些

c++和c语言的区别:1、面向对象编程(OOP)支持不同;2、新增特性不同;3、标准库不同;4、编译方式不同;5、命名空间不同等等。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.14

2288

9

c++和python学习顺序推荐
c++和python学习顺序推荐

一般建议先学习C++,再学习Python,因为这样可以逐步从较为底层的编程语言向更高级的语言过渡。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

1039

6

python和c++学习性价比分析
python和c++学习性价比分析

Python易于学习,广泛应用于Web开发、数据科学和人工智能等领域,但性能较低。C语言性能高,适用于对性能要求较高的场景,如游戏开发和系统编程,但学习曲线陡峭,错误处理复杂。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

447

5

c语言和c++一样吗
c语言和c++一样吗

c语言和c++是两种不同的编程语言,虽然有相似之处,但存在显著差异。c语言专注于过程式编程和系统级开发,以简洁、高效著称。c++作为c语言的超集,引入了面向对象编程,增强了代码组织和管理能力,但学习曲线也更陡峭。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

347

5

c语言和c++先学哪个好
c语言和c++先学哪个好

初学者选择学习c语言还是c++语言,需要根据个人学习目标、背景以及编程兴趣和预期应用方向来决定。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

426

5

c语言和c++的区别和联系
c语言和c++的区别和联系

c语言和c++是计算机科学领域应用广泛的编程语言。虽然它们有着相似的基础,但它们在语言类型、语法功能和内存管理方面存在着显著差异。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

600

5

c++软件中文更改教程
c++软件中文更改教程

对于 ide,可通过打开设置,找到语言设置,选择中文,并保存更改。对于非 ide 应用程序,可查找设置或选项,选择语言设置,更改为中文,并保存更改。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.21

1449

9

python和java和c++学习性价比分析
python和java和c++学习性价比分析

Python以其易学性、丰富的库和活跃的社区而著称,适合数据科学、人工智能和Web开发。Java以其跨平台性、企业级应用开发和Android应用开发而闻名。C++以其底层控制能力、高效性能和游戏开发而著称。选择哪种语言取决于个人兴趣、职业方向和特定需求。想了解更多python和java和c++的相关内容,可以阅读本专题下面的文章。

2024.03.22

1237

7

c++和c语言学习顺序推荐
c++和c语言学习顺序推荐

对于初学者,建议先学习C语言,掌握编程基础后再转入C++,便于理解面向对象编程概念。有编程经验者可直接学习C++,快速接触高级编程技术。想了解更多c++和c语言的相关内容,可以阅读本专题下面的文章。

2024.03.25

1345

9

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习