c++如何实现快速排序算法_c++快排代码实现思路【核心】

1次阅读

快排分区易错的核心在于边界处理混乱;应统一采用左闭右开区间,基准选arr[l],双指针从l+1和r-1开始,停右指针后交换arr[l]与arr[right]。

c++如何实现快速排序算法_c++快排代码实现思路【核心】

快排的分区逻辑为什么总写错?

核心卡点在 partition 函数里边界处理——很多人用 leftright 当闭区间,但选基准后移动指针时没统一规则,导致越界或死循环

  • 推荐固定用「左闭右开」区间:quicksort(arr, l, r) 表示排序 arr[l]arr[r-1],这样递归调用更干净(比如 quicksort(arr, l, pivot)quicksort(arr, pivot + 1, r)
  • 基准值选 arr[l] 最简单;双指针从 l+1r-1 开始向中间扫,遇到 = 基准的停右指针,然后交换
  • 最后把基准换到分界点:交换 arr[l]arr[right](此时 right 是最后一个
  • 别忘了递归前检查区间长度:if (r - l ,否则小数组也递归,反而拖慢速度

std::sort 不能直接替代手写快排?

能,但不是所有场景都该用 std::sort。它底层是混合排序(introsort),平均快、最坏有保障,但无法控制分区策略或插入阈值。

  • 需要稳定分区位置做调试/教学?必须手写 partition
  • 数据有大量重复值?标准库版本可能退化,你得手动加三路划分(low/mid/high 三段)
  • 嵌入式或内存受限环境?std::sort 可能隐式分配临时缓冲区,而手写可全程原地
  • 想测不同 pivot 策略(中位数、随机)对性能影响?只能自己实现

随机 pivot 能防 O(n²) 但要注意什么?

不加随机化,快排在已排序或逆序数组上就是 O(n²),加了之后期望复杂度回到 O(n log n),但实现容易出错。

  • 别在每次递归都调 rand()——要先 srand(time(nullptr)),但只调一次;否则多线程下会崩,且重复 seed 导致重复序列
  • 交换 pivot 到左端再分区:先生成 rand_idx ∈ [l, r-1],再 swap(arr[l], arr[rand_idx])
  • std::random_device + std::mt19937 更靠谱,但注意 c++11 后才稳定支持;老项目慎用
  • 如果数据量小(r - l ),随机化收益几乎为零,不如直接用插入排序

递归太深导致栈溢出怎么压?

快排最坏递归深度 O(n),尤其单边倾斜时,std::stack 模拟或尾递归优化是常见解法,但 C++ 编译器不一定帮你优化尾递归。

立即学习C++免费学习笔记(深入)”;

  • 优先「先递归小半边,再循环处理大半边」:分区后比较左右段长度,对短的那段递归调用,长的那段用 while 循环重置参数继续处理
  • 完全去递归?可用 std::stack<:pair int>></:pair> 存待排区间,每次 pop 一个,分区后 push 两个新区间——但注意 push 顺序影响栈深度
  • 别信「加个 inline 就能消除递归」:编译器对递归函数基本不内联
  • Linux 下默认栈大小约 8MB,若数组超千万级元素,哪怕平衡分割也可能爆栈,此时必须迭代化

实际写的时候,pivot 随机化、小数组切换插入排序、尾递归优化这三点叠加,才能让手写快排在真实数据上既稳又快。漏掉任意一个,都可能在某个数据分布下突然变慢一倍。

text=ZqhQzanResources