排序算法
快速排序算法(递归)
好的,快速排序(Quick Sort)是一种高效的分治排序算法,平均时间复杂度为 O(n log n),最坏情况下(如数组已有序)为 O(n²),但通过优化策略(如随机化 pivot)可以避免最坏情况。以下是它的核心思想和步骤:
1. 核心思想
通过一趟排序将待排序列分割成独立的两部分,其中一部分的所有元素比另一部分小,然后递归地对这两部分排序,最终使整个序列有序。
2. 具体步骤
-
选择基准值(pivot):
从数组中选择一个元素作为基准(通常选第一个、最后一个或随机元素)。 -
分区(Partition):
- 将小于 pivot 的元素移到其左侧,大于 pivot 的元素移到右侧。
- 最终 pivot 会位于其正确的位置(即排序后的最终位置)。
- 分区完成后,数组被划分为两个子数组(左子数组 ≤ pivot,右子数组 > pivot)。
-
递归排序子数组:
对左右子数组重复上述过程,直到子数组长度为 1 或 0(已有序)。
3. 示例(以升序排序为例)
假设数组为 [3, 6, 8, 10, 1, 2, 1],选择最后一个元素 1 为 pivot:
- 分区过程:
- 从左到右遍历,将 ≤
1的元素交换到左侧。 - 最终 pivot
1被交换到中间位置,数组变为[1, 1, 2, 10, 8, 6, 3](pivot 的索引为 1)。
- 从左到右遍历,将 ≤
- 递归:
- 左子数组
[1](已有序),右子数组[2, 10, 8, 6, 3]继续排序。
- 左子数组
4. 代码实现(C++)
#include <iostream>
#include <vector>
using namespace std;
// 分区函数(核心)
int partition(vector<int>& arr, int low, int high) {
int pivot = arr[high]; // 选择最后一个元素作为基准(可优化为随机选择)
int i = low - 1; // i 是小于 pivot 的区域的右边界
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++;
swap(arr[i], arr[j]); // 将小于 pivot 的元素交换到左侧
}
}
swap(arr[i + 1], arr[high]); // 将 pivot 放到正确位置
return i + 1; // 返回 pivot 的索引
}
// 递归排序函数
void quickSort(vector<int>& arr, int low, int high) {
if (low < high) {
int pivotIndex = partition(arr, low, high); // 分区
quickSort(arr, low, pivotIndex - 1); // 递归排序左子数组
quickSort(arr, pivotIndex + 1, high); // 递归排序右子数组
}
}
// 测试代码
int main() {
vector<int> arr = {3, 6, 8, 10, 1, 2, 1};
quickSort(arr, 0, arr.size() - 1);
cout << "Sorted array: ";
for (int num : arr) {
cout << num << " ";
}
return 0;
}
关键点说明(C++ 特性相关)
-
分区优化:
- 上述代码选择最后一个元素作为
pivot,实际工程中可随机选择以避免最坏情况:int pivotIndex = low + rand() % (high - low + 1); swap(arr[pivotIndex], arr[high]); // 将随机 pivot 交换到末尾
- 上述代码选择最后一个元素作为
-
原地排序:
- 通过传递数组引用
vector<int>& arr和下标范围[low, high],避免拷贝开销,符合 C++ 高效特性。
- 通过传递数组引用
-
时间复杂度:
- 平均 O(n log n),最坏 O(n²)(可通过随机化或三数取中法优化)。
-
STL 对比:
- C++ STL 的
std::sort()通常使用快速排序的优化混合版本(如内省排序 IntroSort)。
- C++ STL 的
面试中可能的追问
- 如何避免栈溢出?
答:尾递归优化或改用迭代版本(用栈模拟递归)。 - 为什么快速排序比归并排序更常用?
答:快速排序的常数因子更小,且原地排序节省内存。
5. 关键点
- 不稳定排序:相同元素的相对位置可能改变。
- 优化策略:
- 随机选择 pivot 避免最坏情况。
- 对小规模子数组改用插入排序(减少递归开销)。
- 空间复杂度:
- 递归栈空间平均 O(log n),最坏 O(n)。
6. 对比其他排序
- 归并排序:稳定且始终 O(n log n),但需要额外空间。
- 堆排序:无需额外空间,但缓存局部性较差。
Do not communicate by sharing memory; instead, share memory by communicating.

浙公网安备 33010602011771号