1. 快速排序在C++面试中的核心地位
作为算法面试的"常驻嘉宾",快速排序出现的频率几乎和二叉树遍历不相上下。去年我参与某大厂面试时,连续三轮技术面都被要求手写快排,只是考察的侧重点各不相同——从基础实现到边界处理,再到时间复杂度分析,最后到工程实践中的优化技巧。
为什么面试官如此钟爱这个算法?原因很简单:一个看似简单的快排实现,能同时考察候选人的算法基础、编码规范、边界条件处理能力,以及对递归和分治思想的理解深度。更重要的是,它能真实反映程序员的思维严谨性——据统计,能一次性写出完全正确快排代码的候选人不超过30%。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础版本实现与常见陷阱
2.1 经典递归实现框架
先来看最基础的实现版本,这是90%面试者的起点:
cpp复制void quickSort(vector<int>& arr, int left, int right) {
if (left >= right) return;
int pivot = partition(arr, left, right);
quickSort(arr, left, pivot - 1);
quickSort(arr, pivot + 1, right);
}
这个框架看似简单,但隐藏着几个关键点:
- 终止条件必须是
left >= right而非left == right,因为当子数组长度为1时,left可能大于right - pivot的定位已经确定,所以递归区间要排除pivot本身
- 区间划分必须使用闭区间[left, right],这是工业界的通用做法
2.2 Partition函数的魔鬼细节
真正的难点在于partition实现。以Lomuto分区方案为例:
cpp复制int partition(vector<int>& arr, int left, int right) {
int pivot = arr[right]; // 选择最右元素作为基准
int i = left;
for (int j = left; j < right; ++j) {
if (arr[j] < pivot) {
swap(arr[i], arr[j]);
++i;
}
}
swap(arr[i], arr[right]);
return i;
}
这个实现有三个致命陷阱:
- 当数组已经有序时,时间复杂度退化为O(n²)
- 元素全等时会产生不必要的交换
- 基准值选择不当会导致递归深度失衡
我在面试中曾亲眼见过候选人因为这个partition实现没处理好全等数组的情况而被一票否决。正确的做法应该增加
arr[j] <= pivot的判断,但这样又会降低一般情况下的性能——这就是算法设计的trade-off。
3. 工业级优化策略
3.1 三数取中法优化基准选择
为了避免最坏情况,工程实践中常用"三数取中"法:
cpp复制int medianOfThree(vector<int>& arr, int left, int right) {
int mid = left + (right - left) / 2;
if (arr[left] > arr[mid]) swap(arr[left], arr[mid]);
if (arr[left] > arr[right]) swap(
