基本思想:
任取待排序元素中的某个序列为基准,以该元素值为基准,将序列分成两个子序列。左子序列的元素都小于基准值,右子序列的元素都大于基准值,然后左右序列重复上面的过程,直到所有元素都排列到相应的位置为止。
图解:
代码实现:
主题框架代码:
//快排,我们需要依次递归
void QuickSort(int*a, int begin,int end)
{
if (begin > end)
return;
int key = PartSort(a, begin, end);// PartSort函数实现单次排序
QuickSort(a, begin, key - 1);
QuickSort(a, key + 1, end);
}
单次排序函数代码:
1. 方法一
//Swap函数功能为交换两个数
int PartSort(int* a, int begin, int end)
{
int key = begin;
while (begin < end)
{
while (begin<end&&a[end]>=a[key])
{
--end;
}
while (begin < end&&a[begin] <= a[key])
{
++begin;
}
Swap(&a[begin], &a[end]);
}
Swap(&a[begin], &a[key]);
return begin;
}
2.方法二:坑位法
int PartSort(int* a, int begin, int end)
{
int key = a[begin];
while (begin<end)
{
while (begin < end&&a[end] >= key)
{
--end;
}
a[begin] = a[end];
while (begin < end&&a[begin] <= key)
{
++begin;
}
a[end] = a[begin];
}
a[begin] = key;
return begin;
}
3.方法三:前后指针
int PartSort3(int *a, int begin, int end)
{
int prev = begin - 1;
int cur = begin;
while (cur<end)
{ //以end处元素为key
if (a[cur] < a[end])
{
++prev;
Swap(&a[prev], &a[cur]);
++cur;
}
else
++cur;
}
++prev;
Swap(&a[prev], &a[end]);
return prev;
}
方法三的简洁代码:
int PartSort3(int *a, int begin, int end)
{
int prev = begin - 1;
int cur = begin;
while (cur<end)
{
if (a[cur] < a[end]&&++prev!=cur)
{
Swap(&a[prev], &a[cur]);
}
++cur;
}
Swap(&a[++prev], &a[end]);
return prev;
}
通过刚才的图解的过程,我们发现待排序列为逆序的时候快排效率最低,时间复杂度为O(N^2),然而这种情况是由于我们选择的key值引起的。为了解决这种情况,我们可以采用三数取中的方法。
快排的优化
三数取中+小区间优化(当数据较少的时候,我们可以采用直接插入排序,效率较高)
三数取中代码实现:
int GetMinIndex(int* a, int begin, int end)
{
int min = begin + ((end - begin) >> 1);
if (a[begin] < a[min])
{
if (a[min] < a[end])
{
return min;
}
else
{
if (a[begin] < a[end])
return end;
else
return begin;
}
}
else//a[begin]>a[min]
{
if (a[min]>a[end])
return min;
else
{
if (a[begin] < a[end])
return end;
else
return begin;
}
}
}
快排优化之后的代码实现
int PartSort(int *a, int begin, int end)
{
int min = GetMinIndex(a, begin, end);
Swap(&a[min], &a[begin]);
int key = a[begin];
while (begin<end)
{
while (begin < end&&a[end] >= key)
{
--end;
}
a[begin] = a[end];
while (begin < end&&a[begin] <= key)
{
++begin;
}
a[end] = a[begin];
}
//begin和end一定相遇于坑的位置
a[begin] = key;
return begin;
}
void QuickSort(int*a, int begin, int end)
{
if (begin > end)
return;
if (end - begin + 1 <3)
{
Insertsort(a, end - begin + 1);
}
int key = PartSort3(a, begin, end);
//[begin,key-1] key [key+1,end]
QuickSort(a, begin, key - 1);
QuickSort(a, key + 1, end);
}
非递归方法的代码实现:
非递归的实现借助于栈,将要排序的部分开始,结尾的下标入进栈,表示一段区域。
此处的栈接口代码的具体实现,可参考https://blog.csdn.net/weixin_43519514/article/details/104783366
void QuickSortNonr(int* a, int left, int right)
{
assert(a);
Stack s;
StackInit(&s);
StackPush(&s, left);
StackPush(&s, right);
while (!StackEmpty(&s))
{
int end = StackTop(&s);
StackPop(&s);
int begin = StackTop(&s);
StackPop(&s);
int key = PartSort(a, begin, end);
if (begin < key - 1)
{
StackPush(&s, begin);
StackPush(&s, key - 1);
}
if (key + 1 < end)
{
StackPush(&s, key+1);
StackPush(&s, end);
}
}
StackDestroy(&s);
}
用到的函数代码实现
void Swap(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
插入排序的实现可参考下面的网址
https://editor.csdn.net/md/?articleId=104770087