快速排序
算法思想
选取一个数字x
对数组进行划分。
划分规则:<x
的放在左边,>=x
的在右边。
划分结束,x
的最终位置确定,原问题就转化为了x
左右两边规模更小的相同的子问题,可以按照上述规则继续划分,直到划分的区间长度为1
。
C++实现
// 左闭右开
int partition(vector<int>& nums, int l, int r) {
int index = rand() % (r - l) + l, small = l;
swap(nums[l], nums[index]);
// 小的交换到左边,small指向左区间的最后一个位置
for(int i = l + 1; i < r; ++i) {
if(nums[i] < nums[l]) {
swap(nums[i], nums[++small]);
}
}
swap(nums[l], nums[small]);
return small;
}
void quick_sort(vector<int>& nums, int l, int r) {
if(l >= r) return;
int index = partition(nums, l, r);
quick_sort(nums, l, index);
quick_sort(nums, index + 1, r);
}
稳定性分析
不稳定,体现在两点
- 随机选取
x
假设数字全部相同,随机选取x
之后再进行划分,x
相对于其他元素位置发生了改变,不再稳定。 - 划分函数
在划分过程中有下述状态:
p | lower | higher | unvisited
p
指的是pivotal
,lower
指小于p的部分,unvisited
指还未访问到,|
是分割线。
例如:5 | 3 1 2 | 9 7 8 9 | 4 6 3
这时遍历unvisited
部分 刚到了4 (array[8])
显然4<5
,这是4
应该从unvisited
部分去到lower
部分。 因此higher
部分第一个元素9 (array[4])
和4
互换。
变成了这样:5 | 3 1 2 4 | 7 8 9 9 | 6 3
注意!这时这个9 (array[4])
被换到了 后面那个9 (array[7])
的 后面。这就不稳定了。
参考:
知乎:知遥其实是德鲁伊