一、快速排序的基本思想
快速排序利用了分治的思想,分而治之。通过一趟排序将序列分为两部分,其中一部分比较关键字小,一部分比关键字大。之后继续对这两个子序列重复此过程,直到整个序列都有序。
二、快速排序的三个步骤
- 选基准值:在要排序的序列中选一个几个基准值,作为划分区间的 关键字。通常选取关键字的方式对效率有很大的影响。
- 分割序列:按照基准值把序列分为两部分,左边的小于基准值,右边的大于基准值。
- 重复分割:对子序列重复上面的步骤,知道序列为空或者只有一个元素。当递归处理的所有子序列都返回时,序列有序。
三、三种实现方式
注:下面代码中所有区间都是左闭右开,[ left, right),且排序都是从大到小。且基准值默认选择序列的最后一个元素。
一、版本一填充法
思路:两个指针 begng作为序列的开始 和 end 序列的结束。
将序列的最后一个元素保存起来,作为基准值。
开始划分序列:直到begin < end 不成立
begin 从左往右找比 基准值 大的元素,将该值填充到 end 的位置(end 位置上的值已经保存到 key),end-- ,因为已经划分好了一个元素。
end 从右往左找比 基准值小的元素,如将该值填充到 begin 的位置(begin 位置上的值已经保存到 end位置),begin++,已经划分好一个元素。
循环结束时,将 key 填充到 end 的位置,然后将 end 返回,作为下一次划分序列的边界。
// 版本一 填充法
int partition(vector<int> &v, int left, int right)
{
int begin = left;
int end = right - 1;
int key = v[end]; // 选基准
while (begin < end)
{
while (begin < end && v[begin] <= key)
begin++;
if (begin < end)
v[end--] = v[begin];
while (begin < end && v[end] >= key)
end--;
if (begin < end)
v[begin++] = v[end];
}
v[end] = key;
return end;
}
void QuickSort(vector<int>& v, int left, int right)
{
if (left < right)
{
int boundary = partition(v, left, right);
QuickSort(v, left, boundary);
QuickSort(v, boundary + 1, right);
}
}
二、版本二 交换法
和上面的版本一类似,不同之处是,这里不是填充,而是将找到的元素交换。
// horn版本
int partition(vector<int> &v, int left, int right)
{
int begin = left;
int end = right - 1;
int key = v[end];