1. 程式人生 > >快速排序基本操作的優化(完整程式碼)

快速排序基本操作的優化(完整程式碼)

這裡是快速排序的優化版,在其中的幾個部分進行了優化。
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); }