快速排序是排序很厉害的排序之一
下面介绍一下快排
源码在最后面!!!
(hoare版本)首先看一下快速排序的单趟排序
这个是(hoare版本的单趟排序)
下面是双指针法
单趟,双指针法比较简单(推荐)
下面是如何递归实现
这就是递归实现
可以结合起来看一看
上面的这两个是函数测试用的
通过主函数调用
给展示一下成果
其中这两个测试用例可以测试快排的性能(数据量有点小,如果想要测试的话多放一些数据),其中快排的缺点是对于有顺序呢数据递归实现的话会多次调用函数,最终可能会StackOverflow。
如果对于有序的数据,快排的缺点也是特别明显,可能每次都会取到最大或者最小的数据,导致每次都需要交换数据,所以需要写一个三数取中
下面是三数取中
可以结合上面的代码一块看
有了三数取中就可以让有序的数据也可以快速排序了。
下面是源码
//快排
//三数取中
//三数取中目的:面对有序最坏情况,变成选中位数做key,变成最好情况
int GetMidIndex(int* a, int left, int right)
{
//int mid = (left + right) / 2;
int mid = left + (right - left) / 2;
if (a[left] < a[mid])
{
if (a[mid] < a[right])
{
return mid;
}
else if (a[left] > a[right])
{
return left;
}
else
{
return right;
}
}
else //a[left] >= a[mid]
{
if (a[mid] > a[right])
{
return mid;
}
else if (a[left] < a[right])
{
return left;
}
else
{
return right;
}
}
}
-----------------------------------
//hoare版本
//单趟排序
int Partion(int* a, int left, int right)
{
//三数取中
int mid = GetMidIndex(a, left, right);
Swap(&a[mid], &a[left]);
int keyi = left;//left,right是两个边界位置
while (left < right)
{
//左边做keyi,右边先走
while ((left<right) && (a[right]>= a[keyi]))//找小
{
--right;
}
while ((left < right) && a[left] <= a[keyi])//找大
{
++left;
}
Swap(&a[left], &a[right]);
}
//出来后需要交换最后一个值
Swap(&a[left], &a[keyi]);
return left;
}
------------------------------------
//快排 挖坑法
int Partion2(int* a, int left, int right)
{
//三数取中
int mid = GetMidIndex(a, left, right);
Swap(&a[mid], &a[left]);
int key = a[left];
int pivot = left;
while (left < right)
{
// 右边找小, 放在坑里
while ((left < right) && (a[right] >= key))
{
--right;
}
a[pivot] = a[right];
pivot = right;
// 在走左边,左边找大,放在坑里
while ((left < right) && (a[left] < key))
{
++left;
}
a[pivot] = a[left];
pivot = left;
}
a[pivot] = key;
return pivot;
}
------------------------------------
//双指针 简化
//推荐这种
int Partion3(int* a, int left, int right)
{
//三数取中
int mid = GetMidIndex(a, left, right);
Swap(&a[mid], &a[left]);
int keyi = left;//选择左边做keyi
int prev = left;
int cur = prev + 1;
//prev指向left;
//cur指向left+1;
//先走cur,找比a[keyi]小的,找到后++prev,在交换a[prev]和a[cur];
while (cur <= right)
{
if (a[cur] < a[keyi] && ++prev != cur)
{
Swap(&a[prev], &a[cur]);
}
++cur;
}
Swap(&a[keyi], &a[prev]);
return prev;
}
------------------------------------
//快速排序
//时间复杂度:O(N*logN)
void QuickSort(int* a, int left, int right)
{
if (left >= right)
{
return;
}
// 小区间优化, 当分割到小区间时, 不在用递归思想让这段区间有序
// 对于递归快排减少递归次数
if (right - left+1 < 10)
{
InsertSort(a + left, right - left + 1);
}
else
{
int keyi = Partion3(a, left, right);
//[left,keyi-1] keyi [keyi+1,right]
QuickSort(a, left, keyi - 1);
QuickSort(a, keyi + 1, right);
}
}