在上一篇部落格中已經討論過關於快速排序如何優化的問題,這次就直接貼出完整已優化的程式碼。此程式碼優化步驟包括了三數取中選取樞軸+小陣列使用插排+三向切分。
完整程式碼:
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100 //用於要排序陣列的最大值
#define MAX_LENGTH_INSERT_SORT 7 //陣列長度閾值
typedef struct //定義一個順序表結構
{
int r[MAXSIZE+1]; //用於儲存要排序陣列,r[0]用作哨兵或者臨時變數
int length; //用於儲存順序表的最大長度
}SqList;
void swap(SqList *L,int i,int j);
void InsertSort(SqList *L);
void PickMiddle(SqList *L,int low,int high);
int Partition(SqList *L,int low,int high);
void QSort(SqList *L,int low,int high);
void QuickSort(SqList *L);
int main()
{
int i;
int array[] = {39,80,76,41,13,29,50,78,30,11,100,7,41,86,41,11,30};
SqList L;
L.length = sizeof(array)/sizeof(array[0]); //獲取陣列長度
printf("Before sorting:");
for(i=0;i<L.length;i++)
{
L.r[i+1]=array[i]; //把陣列存入順序表結構
printf("%d ",L.r[i+1]);
}
printf("\n\n");
QuickSort(&L);
printf("After sorting: ");
for(i=0;i<L.length;i++) //輸出排序後的陣列
printf("%d ",L.r[i+1]);
return 0;
}
/*元素交換函式*/
void swap(SqList *L,int i,int j)
{
int temp=L->r[i];
L->r[i]=L->r[j];
L->r[j]=temp;
}
/*快速排序主函式*/
void QuickSort(SqList *L)
{
QSort(L,1,L->length); //L->r[0]作為哨兵,low從1開始
}
/*快排處理函式*/
void QSort(SqList *L,int low,int high)
{
/* if-else條件語句用於處理小陣列處理的問題,
* 具體序列值說法不一,此處定為7(也有認為50合理)。若陣列
* 個數較小採用簡單插入排序,效率更高。*/
if((high-low) <= MAX_LENGTH_INSERT_SORT)
{
InsertSort(L);
return;
}
PickMiddle(L,low,high); //三數取中函式
int lt = low; //low此時為樞軸位置
int gt = high;
int i = low +1; //low位置的元素為樞軸元素,所以用於比較的元素從low+1開始
L->r[0]=L->r[low]; //將樞軸的元素儲存到L->r[0]中
while(i<=gt)
{
if(L->r[i] < L->r[0]) //小於樞軸元素的放在lt左邊
swap(L,lt++,i++); //即交換lt和i位置的元素,此時樞紐位置(lt)右移一位,i也因此右移
else if(L->r[i] > L->r[0]) //大於樞軸元素的放在gt右邊
swap(L,i,gt--); //交換i和gt位置的元素,gt需要左移,i由於變為gt位置元素,所以不需要移動
else //相等時,無需交換,只需把i右移一位
i++;
}
//lt-gt的元素已經排定(相等的元素),只需對it左邊和gt右邊的元素進行遞迴求解
QSort(L,low,lt-1);
QSort(L,gt+1,high);
}
/*三數取中函式*/
void PickMiddle(SqList *L,int low,int high)
{
int mid = (low+high) / 2; //計算陣列中間元素的下標
if(L->r[low]>L->r[high])
swap(L,low,high); //目標[low]<=[high]
if(L->r[mid]>L->r[high])
swap(L,mid,high); //目標[mid]<=[high]
//以上兩步保證把最大移到最右端
if(L->r[mid]>L->r[low])
swap(L,mid,low); //目標[low]>=[mid],即把中間值移到最左端
//此時,L->r[mid] <= L->r[low] <= L->r[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];
}
}
}
複製程式碼
執行結果為: