快速排序的基本思想
通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可以分别对这两部分记录继续进行排序,以达到整个序列有序的目的。
快排特征
(1)快速排序在最坏情况下,算法的时间复杂度为O(nlogn);
(2)由于关键字的比较和交换是跳跃进行的,因此,快排不是一种稳定的排序算法。
#include <iostream>
using namespace std;
#define MAXSIZE 1000
typedef struct
{
int r[MAXSIZE+1]; /* 用于存储要排序数组,r[0]用作哨兵或临时变量 */
int length; /* 用于记录顺序表的长度 */
}SqList;
void swap(SqList *L,int i,int j)
{
int temp=L->r[i];
L->r[i]=L->r[j];
L->r[j]=temp;
}
/*
*Partition函数,先选取当中一个关键字,使它的左边
*的值都比它小,右边的值都比它大,作为枢轴
*/
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;
}
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);
}
}
void QuickSort(SqList *L)
{
QSort(L,1,L->length);
}
void print(SqList L)
{
for(int i=0; i < L.length; i++)
printf("%5d",L.r[i+1]);
printf("\n");
}
#define N 9
int main()
{
int d[N] = {50,10,90,30,70,40,80,60,20};
SqList La;
for(int i = 0; i < N; i++)
La.r[i+1] = d[i];
La.length = N;
QuickSort(&La);
print(La);
return 0;
}
优化方面
(1)选取枢轴:每次选取的pivot是固定的,如果遇到极端的情况(最大或最小),就会增加复杂度。
改进方法:随机选取pivot,如三数取中(或多数中取中)
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,high,m); //high位置已经放了最大值了
if(L->r[m] > L->r[low])
swap(L,m,low);
pivotkey = L->r[low];
(2)不必要的交换:Partition函数,比如50关键字位置变化了多次,而最终目标是5。
int Partition_v1(SqList *L,int low, int high)
{
int pivotkey;
pivotkey = L->r[low];
L->r[0] = pivotkey;
while(low < high)
{
while(low < high && L->r[hign] >= 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)数组大小:快排适合数据规模较大的情况,因此,可以选取一个阀值(数据量)
#define MAX_LENGTH_INSERT_SORT 7
/*
直接插入排序(升序)
插入排好序的序列中
*/
void InsertSort(SqList *L)
{
int i,j;
for(i=2;i<=L->length;i++)
{
if (L->r[i]<L->r[i-1]) /* 需将L->r[i]插入有序子表 */
{
L->r[0]=L->r[i]; /* 设置哨兵 */
for(j=i-1;L->r[j]>L->r[0];j--)
L->r[j+1] = L->r[j]; /* 记录后移 */
L->r[j+1] = L->r[0]; /* 插入到正确位置 */
}
}
}
void QSort(SqList *L, int low, int high)
{
int pivot;
if((hign - low) > MAX_LENGTH_INSERT_SORT)
{
pivot = Partion_v1(L,low,high);
QSort(L,low,pivot-1);
QSort(L,pivot+1,high);
}
else
InsertSort(L);
}