引言
快速排序又叫快排,在排序算法中的地位可谓是举足轻重,它是C语言中qsort函数和C++中sort函数的底层排序算法。同时作为与它同为交换排序的冒泡排序,其效率和性能与快排相差很多。本片博客会重点介绍快排的算法逻辑、效率分析以及代码和效率优化。
快速排序的基本逻辑
快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。
简单来讲就是:
1.从待排序的元素序列中随机选取一个数,我们称该元素为k。
2.接下来把小于k的放在k的左边,大于k的放在k的右边。
3.最后从k位置分成左右两个序列,左右两个序列重复上述操作,直到有序。
我们可以看出这是一个分治的思想,我们仅需要完成一层排序,剩下的进行递归即可。
快速排序层排序实现
算法实现之前,请大家先看一下如下gif动图的快排层排序实现。
第一步,选取序列中第一个元素作为基准值,用变量key记录基准值的下标。
第二步,定义两个下标变量,分别为L和R。L是从序列左边走向序列右边,R是从序列右边走向序列左边。
第三步,让R先走,此时就需要讨论R的停止条件。
1.如果R位置的数值比key位置的数值小,R就停下。
2.如果R遇到L,R就停下。
分析R停下来以后的情况。
如果R停下是因为条件一,那么L开始走,L位置的数值直到比key位置的数值大就停下,在L和R位置的数值交换。重复第二步。
如果R停下是因为条件二,那么R(L)位置的数值与key位置的数值交换,然后把L给了key层排序结束。
接下来是代码的实现
void Swap(int* a, int* b)
{
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
void PartSort(int* a, int L,int R)
{
int key = L;
while (L < R)
{
while (L < R && a[R] >= a[key])
{
R--;
}
while (L <R && a[L] <= a[key])
{
L++;
}
Swap(&a[L], &a[R]);
}
Swap(&a[L], &a[key]);
key=L;
}
快排的层排序目前已经结束了,接下来是快排的整体排序。
快速排序整体排序算法实现
有了快排层排序算法的基础,快排的整体排序就变得容易许多,接下来要用到分治思想。
在层排序之后,L与R重合,此时应该从重合位置断开,分为左右两个序列,这两个序列的特点分别是左边序列的数均小于重合位置的数值,右边序列的数值均大于重合位置的数值,此时分别对两个序列进行层排序。
对左边序列进行分析,此时的L仍为数组首元素的下标,R为上一层的key-1.
对右边序列进行分析,此时的L为上一层的key+1,R仍为数组的最右端。
下面的快速排序的代码实现
void Swap(int* a, int* b)
{
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
void QuickSort1(int* a, int left, int right)
{
int begin = left;
int end = right;
int keyi = begin;
if (begin >= end)
return;
while (left <right)
{
while (left < right && a[right] >= a[keyi])
{
right--;
}
while (left<right && a[left]<=a[keyi])
{
left++;
}
Swap(&a[left], &a[right]);
}
Swap(&a[keyi], &a[left]);
keyi = left;
QuickSort1(a, begin, keyi - 1);
QuickSort1(a, keyi + 1, end);
}