快速排序的基本思想是:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。快速排序算法的时间复杂度为O(nlogn)。由于关键字的比较和交换是跳跃进行的,因此,快速排序是一种不稳定的排序方法。
void QuickSort(SqList *L)
{
QSort(L, 1, L->length);
}
void QSort(SqList *L, int low, int high)
{
int pivot;
if (low < high)
{
pivot = Partition(L, low, high);
QSort(L, low, pivot - 1);
QSort(L, pivot + 1, high);
}
}
int Partition(SqList *L, int low, int high)
{
int pivotkey;
pivotkey = L->r[low];
while (low < high)
{
while (low < high && L->r[high] >= pivotkey)
high--;
swap(L, low, high);
while (low < high && L->r[low] <= pivotkey)
low++;
swap(L, low, high);
}
return low;
}
Partition函数要做的,就是先选取当中的一个关键字,然后想尽办法把它放到一个位置,使得它左边的值都比它小,右边的值比它大,我们将这样的关键字称为
枢轴。
快速排序的优化:
1、优化选取枢轴
三数取中法:即取三个关键字先进行排序,将中间数作为枢轴,一般是取左端、右端和中间三个数。
//优化选取枢轴
int pivotkey;
int m = low + (high - low) / 2;
if (L->r[low] > L->r[high])
swap(L, low, high);
if (L->r[m] > L->r[high])
swap(L, m, high);
if (L->r[m] > L->r[low])
swap(L, m, low);
pivotkey = L->r[low];
2、优化不必要的交换
//优化不必要的交换
int Partition1(SqList *L, int low, int high)
{
int pivotkey;
pivotkey = L->r[low];
L->r[0] = pivotkey;
while (low < high)
{
while (low < high && L->r[high] >= pivotkey)
high--;
L->r[low] = L->r[high];
while (low < high && L->r[low] <= pivotkey)
low++;
L->r[high] = L->r[low];
}
L->r[low] = L->r[0];
return low;
}
3、优化小数组时的方案
如果数组非常小,其实快速排序反而不如直接插入排序来得更好。增加一个判断,当high-low不大于某个常数时(有资料认为7比较合适),就用直接插入排序。
#define MAX_LENGTH_INSERT_SORT 7
void QSort(SqList *L, int low, int high)
{
int pivot;
if ((high - low) > MAX_LENGTH_INSERT_SORT)
{
pivot = Partition(L, low, high);
QSort(L, low, pivot - 1);
QSort(L, pivot + 1, high);
}
else
InsertSort(L);
}
4、优化递归操作
//优化递归操作
void QSort1(SqList *L, int low, int high)
{
int pivot;
if ((high - low) > MAX_LENGTH_INSERT_SORT)
{
while (low < high)
{
pivot = Partition1(L, low, high);
QSort1(L, low, pivot - 1);
low = pivot + 1;
}
}
else
InsertSort(L);
}