一.hoare划分法
根据基准值,将数组划分成前后两部分,前面的部分值小于基准值,后面的值大于基准值。先从后往前找到第一个小于基准值的元素,然后从前向后找到第一个大于基准值的元素,交换这两个元素。如此进行下去,用start和end标记起始位置和结束位置,在遍历的时候更新start和end。划分结束之后start和end相等,都指向最后一个小于等于基准值的元素。因此最后一步需要将基准值和该元素交换,则完成了一次划分。
二.挖坑划分法
先保存基准值,从后往前找第一个小于基准值的元素,将其直接放入原先start处,然后从start往后找第一个大于基准值的元素,找到之后将其放入end处。这样start之前的元素始终小于等于基准值,end之后的元素始终大于等于基准值。当start等于end时,循环结束,此时start和end指向的时候最后一个小于等于基准值的元素。因此最后直接将基准值放入start或end中,划分完成。
三.前后指针划分法
定义一个pre指针始终指向最后一个小于等于基准值的元素,另一个指针cur遍历数组。当遇到小于等于基准值的元素时,需要更新++pre,且要交换pre和cur指向的元素。原因是cur和pre之间可能存在大于基准值的元素。最后交换最后一个小于等于基准值的元素和基准值,划分完成。
四.具体代码*
//三数取中法
int getMid(int* arr, int start, int end) {
int mid = (start + end) / 2;
if (arr[start] > arr[mid]) {
int tmp = start;
start = mid;
mid = tmp;
}
if (arr[mid] > arr[end]) {
int tmp = mid;
mid = end;
end = tmp;
}
return arr[start] < arr[mid] ? mid : start;
}
//hoare划分方法
int partion1(int* arr, int start, int end) {
//取中间值作为基准值
int mid = getMid(arr, start, end);
//交换 mid 和 start
Swap(arr, mid, start);
//选取基准值
int key = arr[start], keyPos = start;
while (start < end) {
//从后向前找第一个小于key的位置
while (start < end && arr[end] >= key)
end--;
//从前往后找第一个大于key的位置
while (start < end && arr[start] <= key)
start++;
//交换end和start处的元素
Swap(arr, end, start);
}
//将基准值处和相遇位置处交换
Swap(arr, end, keyPos);
return end;
}
//挖坑划分法
int partion2(int* arr, int start, int end) {
//取中间值作为基准值
int mid = getMid(arr, start, end);
//交换 mid 和 start
Swap(arr, mid, start);
int key = arr[start];
while (start < end) {
//从后往前找第一个小于key的位置
while (start < end && arr[end] >= key)
end--;
//将元素填入坑中
arr[start] = arr[end];
//从前往后找第一个大于key的位置
while (start < end && arr[start] <= key)
start++;
arr[end] = arr[start];
}
//将基准值填入坑中
arr[start] = key;
return start;
}
//前后指针划分法
int partion3(int* arr, int start, int end) {
//取中间值作为基准值
int mid = getMid(arr, start, end);
//交换 mid 和 start
Swap(arr, mid, start);
int key = arr[start];
//最后一个小于基准值的位置
int pre = start;
//下一个小于基准值的位置
int cur = start + 1;
while (cur <= end) {
//新发现的小数据和尾指针指向的位置不连续,则中间含有大于基准值的数据,故进行交换
//大数据向后移动,小数据向前移动
if (arr[cur] < key && ++pre != cur)
Swap(arr, pre, cur);
++cur;
}
Swap(arr, pre, start);
return pre;
}
void quickSort(int* arr, int start, int end) {
if (start >= end)
return;
//根据基准值划分区间
int keyPos = partion3(arr, start, end);
//左右区间分别排序
quickSort(arr, 0, keyPos - 1);
quickSort(arr, keyPos + 1, end);
}