以上图为例:
指定一个数为a[key] = 6,a[right] 从尾出发找比 6 小的数,找到后停下,接着a[left] 从头出发找比 6 大的数,找到后停下 → Swap(&a[left], &a[right])
,最终 a[right] 和 a[left] 相遇 → Swap(&a[key], &a[right]);//left==right
Swap(&a[key], &a[right]);//left==right
分析:while (left < right)
{
while (a[right] > a[key])
{
--right;
}
while (a[left] < a[key])
{
++left;
}
Swap(&a[left], &a[right]);
}
Swap(&a[key], &a[right]);//left==right
6 | 6 | 6 | ||||||
---|---|---|---|---|---|---|---|---|
a[key] | a[left] | a[right] |
Swap之后:
6 | 6 | 6 | ||||||
---|---|---|---|---|---|---|---|---|
a[key] | a[left] | a[right] |
这样循环就会卡住
while (left < right)
{
while (a[right] > a[key]){}//循环不进入
while (a[left] < a[key]){}//循环不进入
Swap(&a[left], &a[right]);//一直无限循环Swap
}
while (left < right)
{
while (a[right] >= a[key]){
--right;
}
while (a[left] <= a[key]){
++left;
}
Swap(&a[left], &a[right]);
}
right 飞出去的情况:
6 | 7 | 8 | 9 | 6 | 10 | 6 | 13 | 14 |
---|---|---|---|---|---|---|---|---|
a[key] |
left 飞出去的情况:
6 | 1 | 6 | 4 | 5 | 3 | 6 | 2 | 3 |
---|---|---|---|---|---|---|---|---|
a[key] |
因此,right 和 left 每次改变之后都需要判断是否 left < right
int hoareSort1(int* a, int left, int right)
{
assert(a);
if (left >= right)
return;
int key = left, begin = left, end = right;
while (left < right)
{
while (left < right && a[right] >= a[key])
{
--right;
}
while (left < right && a[left] <= a[key])
{
++left;
}
Swap(&a[left], &a[right]);
}
Swap(&a[key], &a[right]);//left==right
//[begin,left-1] [right+1,end]
hoareSort1(a, begin, left - 1);
hoareSort1(a, right + 1, end);
return right;
}
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|
[begin] | [middle] | [end] |
∵ 1 < 6 < 9
∴ 选择 a[middle] 作为 a[key]
// 三数取中
int GetMidIndex(int* a, int left, int right)
{
int begin = left, end = right;
int middle = (left + right) / 2;
if (a[begin] < a[end])
{
if (a[middle] < a[begin])
return begin;
else if (a[middle] > a[end])
return end;
else
return middle;
}
else
{
if (a[middle] < a[end])
return end;
else if (a[middle] > a[begin])
return begin;
else
return middle;
}
}
// 快速排序hoare版本
int hoareSort1(int* a, int left, int right)
{
assert(a);
if (left >= right)
return;
int key = left, begin = left, end = right;
int mid = GetMidIndex(a, left, right);
Swap(&a[mid], &a[key]);
while (left < right)
{
while (left < right && a[right] >= a[key])
{
--right;
}
while (left < right && a[left] <= a[key])
{
++left;
}
Swap(&a[left], &a[right]);
}
Swap(&a[key], &a[right]);//left==right
//[begin,left-1] [right+1,end]
hoareSort1(a, begin, left - 1);
hoareSort1(a, right + 1, end);
return right;
}
⭐int mid = GetMidIndex(a, left, right);
⭐Swap(&a[mid], &a[key]);
时间复杂度分析:针对局部有序或有序的情况效率明显提升
时间复杂度为 O(N) = N*logN
int hoareSort1(int* a, int left, int right)
{
assert(a);
if (left >= right)
return;
if ((right - left + 1) < 5)
{
InsertSort(a + left, right - left + 1);
}
else
{
int key = left, begin = left, end = right;
int mid = GetMidIndex(a, left, right);
Swap(&a[mid], &a[key]);
while (left < right)
{
while (left < right && a[right] >= a[key])
{
--right;
}
while (left < right && a[left] <= a[key])
{
++left;
}
Swap(&a[left], &a[right]);
}
Swap(&a[key], &a[right]);//left==right
//[begin,left-1] [right+1,end]
hoareSort1(a, begin, left - 1);
hoareSort1(a, right + 1, end);
}
return right;
}
把选定做 key 的数存储在新变量中。left 和 right 找到 数 填坑里,原位置变新坑。
// 快速排序挖坑法
int HoleSort2(int* a, int left, int right)
{
if (left >= right)
return;
int key = a[left];
int hole = left, begin = left, end = right;
while (left < right)
{
while (left < right && a[right] >= key)
{
--right;
}
a[hole] = a[right];
hole = right;
while (left < right && a[left] <= key)
{
++left;
}
a[hole] = a[left];
hole = left;
}
a[right] = key;
//[begin,left-1] [right+1,end]
HoleSort2(a, begin, left - 1);
HoleSort2(a, right + 1, end);
return right;
}
cur 找到 比 data 小的数时的情况:
循环结束的情况:
// 快速排序前后指针法
int PointSort3(int* a, int left, int right)
{
assert(a);
if (left >= right)
return;
int keyi = left;
int prev = left, cur = left;
while (cur <= right)
{
if (a[cur] < a[keyi] && cur != prev)
Swap(&a[++prev], &a[cur]);
++cur;
}
Swap(&a[keyi], &a[prev]);
//[left,prev-1][prev+1,right]
PointSort3(a, left, prev - 1);
PointSort3(a, prev + 1, right);
return prev;
}
利用数据结构栈 → 广度遍历
递归→ 深度遍历
[begin,end]
存入栈中[begin,end]
,在这个区间内进行快排[begin,end] → [begin,keyi-1] keyi [keyi+1,end]
,将其存入栈中(注意顺序)[keyi+1,end]
,在在这个区间内进行快排// 快速排序 非递归实现
#include "Stack.h"
void QuickSort(int* a, int left, int right)
{
assert(a);
Stack st;
StackInit(&st);
StackPush(&st, left);
StackPush(&st, right);
while (!StackEmpty(&st))
{
int end = StackTop(&st);
StackPop(&st);
int begin = StackTop(&st);
StackPop(&st);
int keyi = hoareSort1(a, begin, end);//快排
//[begin,keyi-1] keyi [keyi+1,end]
if (keyi + 1 < end)
{
StackPush(&st, keyi + 1);
StackPush(&st, end);
}
if (begin < keyi - 1)
{
StackPush(&st, begin);
StackPush(&st, keyi - 1);
}
}
StackDestroy(&st);
}
// 快速排序递归实现
// 三数取中
int GetMidIndex(int* a, int left, int right)
{
int begin = left, end = right;
int middle = (left + right) / 2;
if (a[begin] < a[end])
{
if (a[middle] < a[begin])
return begin;
else if (a[middle] > a[end])
return end;
else
return middle;
}
else
{
if (a[middle] < a[end])
return end;
else if (a[middle] > a[begin])
return begin;
else
return middle;
}
}
// 快速排序hoare版本
int hoareSort1(int* a, int left, int right)
{
assert(a);
if (left >= right)
return;
if ((right - left + 1) < 5)
{
InsertSort(a + left, right - left + 1);
}
else
{
int key = left, begin = left, end = right;
int mid = GetMidIndex(a, left, right);
Swap(&a[mid], &a[key]);
while (left < right)
{
while (left < right && a[right] >= a[key])
{
--right;
}
while (left < right && a[left] <= a[key])
{
++left;
}
Swap(&a[left], &a[right]);
}
Swap(&a[key], &a[right]);//left==right
//[begin,left-1] [right+1,end]
hoareSort1(a, begin, left - 1);
hoareSort1(a, right + 1, end);
}
return right;
}
// 快速排序挖坑法
int HoleSort2(int* a, int left, int right)
{
if (left >= right)
return;
int key = a[left];
int hole = left, begin = left, end = right;
while (left < right)
{
while (left < right && a[right] >= key)
{
--right;
}
a[hole] = a[right];
hole = right;
while (left < right && a[left] <= key)
{
++left;
}
a[hole] = a[left];
hole = left;
}
a[right] = key;
//[begin,left-1] [right+1,end]
HoleSort2(a, begin, left - 1);
HoleSort2(a, right + 1, end);
return right;
}
// 快速排序前后指针法
int PointSort3(int* a, int left, int right)
{
assert(a);
if (left >= right)
return;
int keyi = left;
int prev = left, cur = left;
while (cur <= right)
{
if (a[cur] < a[keyi] && cur != prev)
Swap(&a[++prev], &a[cur]);
++cur;
}
Swap(&a[keyi], &a[prev]);
//[left,prev-1][prev+1,right]
PointSort3(a, left, prev - 1);
PointSort3(a, prev + 1, right);
return prev;
}
// 快速排序 非递归实现
void QuickSort(int* a, int left, int right)
{
assert(a);
Stack st;
StackInit(&st);
StackPush(&st, left);
StackPush(&st, right);
while (!StackEmpty(&st))
{
int end = StackTop(&st);
StackPop(&st);
int begin = StackTop(&st);
StackPop(&st);
int keyi = hoareSort1(a, begin, end);
//[begin,keyi-1] keyi [keyi+1,end]
if (keyi + 1 < end)
{
StackPush(&st, keyi + 1);
StackPush(&st, end);
}
if (begin < keyi - 1)
{
StackPush(&st, begin);
StackPush(&st, keyi - 1);
}
}
StackDestroy(&st);
}