void Swap(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void QSort(int* a, int left, int right)
{
if (left >= right)//递归结束条件
return;
int begin = left, end = right;
//使用三种方法的其中一种进行单趟排序
int mid = Part3(a, begin, end);//记录每一次排好的元素下标
QSort(a, begin, mid - 1);//递归左右子数组
QSort(a, mid + 1, end);
}
递归调用会将整个数组不断地分为两个子数组,如果递归传入的left和right相等,不用进行排序,如果left大于right,不符合区间的逻辑,也不需要排序。所以递归的结束条件为 left >= right。
3.1 霍尔法
cpp复制代码
//霍尔法
int Part1(int* a, int left, int right)
{
int keyi = left;
int begin = left, end = right;
while (begin < end)
{
while (begin < end && a[end] >= a[keyi])
{
end--;
}
while (begin < end && a[begin] <= a[keyi])
{
begin++;
}
Swap(&a[begin], &a[end]);
}
Swap(&a[keyi], &a[begin]);
return begin;
}
3.2 挖坑法
cpp复制代码
//挖坑法
int Part2(int* a, int left, int right)
{
int key = a[left];
int hole = left;
int begin = left, end = right;
while (begin < end)
{
while (begin < end && a[end] >= key)
{
end--;
}
a[hole] = a[end];
hole = end;
while (begin < end && a[begin] <= key)
{
begin++;
}
a[hole] = a[begin];
hole = begin;
}
a[hole] = key;
return hole;
}
3.3 前后指针法
cpp复制代码
//前后指针法
int Part3(int* a, int left, int right)
{
int keyi = left;
int prev = left;
int cur = prev + 1;
while (cur <= right)
{
if (a[cur] <= a[keyi])
{
prev++;
Swap(&a[cur], &a[prev]);
}
cur++;
}
Swap(&a[keyi], &a[prev]);
return prev;
}
//三数取中
int FindMid(int* a, int left, int right)
{
int mid = (left + right) >> 1;
if (a[left] < a[mid])
{
if (a[mid] < a[right])
return mid;
else //a[mid] >= a[right] mid最大,选left和right中最大的
{
if (a[left] > a[right])
return left;
else
return right;
}
}
else //a[left] >= a[mid]
{
if (a[mid] > a[right])
return mid;
else //a[mid] <= a[right] mid最小,选left和right中最小的
{
if (a[right] < a[left])
return right;
else
return left;
}
}
}
加入了三数取中,快速排序的核心代码就变成了:
cpp复制代码
void QSort(int* a, int left, int right)
{
if (left >= right)
return;
int begin = left, end = right;
int middle = FindMid(a, left, right);
Swap(&a[left], &a[middle]);//交换
int mid = Part3(a, begin, end);
QSort(a, begin, mid - 1);
QSort(a, mid + 1, end);
}