1. 快速排序与随机枢轴概述
快速排序作为最经典的排序算法之一,自1960年由Tony Hoare提出以来,凭借其平均O(nlogn)的时间复杂度和原地排序的特性,一直是实际应用中最常用的排序算法。但传统快速排序在选择固定枢轴(如总是选择第一个或最后一个元素)时,面对已排序或接近排序的输入数据,性能会退化到O(n²)。这正是随机枢轴技术要解决的核心问题。
随机枢轴的核心思想很简单:在每次划分前,随机选择数组中的一个元素作为枢轴。这种随机性打破了特定输入模式可能导致的性能陷阱。想象你在玩扑克牌时,如果每次都固定从某个位置切牌,对手很容易预测你的牌序;而随机切牌则能确保公平性。同样的道理,随机枢轴让算法对各种输入数据都保持"公平"的处理效率。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 分区方案深度解析
2.1 Lomuto分区方案详解
Lomuto分区是最直观的实现方式,其核心逻辑可以概括为"维护一个分界线":遍历数组时,将所有小于枢轴的元素都移动到这条线的左侧。具体实现中,我们用变量i来标记这条分界线:
cpp复制int partition(int arr[], int low, int high) {
int pivot = arr[high]; // 选择最后一个元素作为枢轴
int i = low; // 分界线初始位置
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
swap(arr[i], arr[j]);
i++; // 分界线向右移动
}
}
swap(arr[i], arr[high]); // 将枢轴放到最终位置
return i;
}
关键细节:Lomuto分区总是选择最后一个元素作为枢轴,这使得在随机枢轴实现中需要先进行一次交换操作。这也是为什么在partition_r函数中要先交换随机选择的枢轴到末尾位置。
2.2 Hoare分区方案剖析
Hoare分区是快速排序发明者最初提出的方案,相比Lomuto更加高效,其核心思想是从两端向中间扫描:
cpp复制int partition(int arr[], int low, int high) {
int pivot = arr[low]; // 选择第一个元素作为枢轴
int i = low - 1, j = high + 1;
while (true) {
do { i++; } while (arr[i] < pivot); // 从左找大于枢轴的
do { j--; } while (arr[j] > pivot); // 从右找小于枢轴的
if (i >= j) return j; // 相遇时返回
swap(arr[i], arr[j]);
}
}
Hoare分区有两个显著特点:1) 它不保证枢轴元素在最终的正确位置上;2) 分区后的两个子数组是[low, j]和[j+1, high]。这意味着递归调用时需要包含j位置,这与Lomuto方案不同。
3. 随机枢轴的实现艺术
3.1 随机数生成的关键细节
在C++中生成高质量的随机数需要注意几个要点:
cpp复制int partition_r(int arr[], int low, int high) {
// 初
