快速排序基本操作的优化(完整代码)

来源:互联网 发布:dafa888信誉第一js 编辑:程序博客网 时间:2024/06/03 21:53

这里是快速排序的优化版,在其中的几个部分进行了优化。
1、设置某一常数,当(high-low)大于某个数时,用快排递归,小于时,用直接插入排序。
当待排数组比较小时,用快速排序递归操作,反而不如用直接插入排序来的快。直接插入排序是简单排序中性能最好的。
2、用L->r【0】存储枢轴数据,等到low和high汇合后,确定了枢轴位置,再将L->r【0】赋值给L->r【low】。
经典的快排,是将枢轴数据pivot,通过与表中其他元素比较,逐次换到合适的位置。为了减少这其中不必要的交换,我们用L->r【0】备份枢轴数据。最后一步再赋值给L->r【low】。
3、选取三个元素,取其中的中间值作为枢轴。
经典的快速排序中,是选取左端第一个数据作为枢轴,如果第一个数据比较大或比较小,会很大程度上影响快排的速度。三数取中,则以极大的概率避免了这种情况。这里我们分别选取了左端、中间和右端三个数据。
4、用迭代替换部分递归(尾递归)
经典快速排序,是排好当前表后,递归排序其低子表和高子表,这里,在递归完低子表后,用pivot替换low的值,继续循环,就可以排序高子表了。

//快速排序(优化版)#include<stdio.h>#include<stdlib.h>#define MAXSIZE 20      //待排序数据个数 #define MAX_LENGTH 7        //大于MAX_LENGTH用快排递归,小于,用直接插入排序typedef struct {    int r[MAXSIZE+1];    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;}//将比枢轴pivotkey小的元素放到左边,大的放到右面,然后将pivotkey放入合适的位置int Partition(SqList *L,int low,int high){    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,high,m);    if(L->r[m]>L->r[low])        swap(L,low,m);      //这一段意思是,选左端、中间、右端三个数,然后三数取中作为枢轴                            //避免了直接去左端作为枢轴时,左端恰好是很小或很大的情况    pivotkey=L->r[low];     //将第一个元素作为枢轴pivotkey    L->r[0]=pivotkey;       //将枢轴关键字存入L->r【0】    while(low<high)     //从表的两端交替向中间扫描    {        while(low<high && L->r[high]>=pivotkey)     //从右边起,将比pivotkey小的换到左边            high--;        L->r[low]=L->r[high];       //采用替换而不是交换的方式,避免了多余的交换操作        while(low<high && L->r[low]<=pivotkey)      //从左边起,将比pivotkey大的换到右边            low++;        L->r[high]=L->r[low];       //采用替换而不是交换的方式,避免了多余的交换操作    }    L->r[low]=L->r[0];      //将枢轴值替换回L->r【low】    return low;     //low与high相等时,即为枢轴位置}//直接插入排序//直插的经典代码void InsertSort(SqList *L){    int i,j;    for(i=2;i<=L->length;i++)    {        if(L->r[i]<L->r[i-1])        {            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((high-low)>MAX_LENGTH)       //大于MAX_LENGTH用快排递归,小于,用直接插入排序    {        while(low<high)     //用while替换if                            //一次循环后,low没用了,将pivot替换low,再循环一次,就去排序高子表了                            //这是用迭代替换了部分递归        {            pivot=Partition(L,low,high);        //将表一分为二            QSort(L,low,pivot-1);       //低子表继续递归            low=pivot+1;        }    }    else        InsertSort(L);}//初始化函数int Init(SqList ** L){    *L=NULL;    *L=(SqList *)malloc(sizeof(SqList));    if(*L==NULL)        {            return 0;        }    (*L)->length=0;    return 1;}//插入函数void Insert(SqList **L,int data){    (*L)->length++;    (*L)->r[(*L)->length]=data;} //输出函数void Printf(SqList *L){    int i;    for(i=1;i<=L->length;i++)    {        printf("%d ",L->r[i]);    }}//主函数void main(){    SqList *L;    int i;    Init(&L);    int a[]={55,44,11,22,33,77,45,68,95,61,            89,632,114,236,895,145,71,33,54,147};    for(i=0;i<20;i++)    {        Insert(&L,a[i]);    }    QSort(L,1,L->length);    InsertSort(L);    Printf(L);}
0 0