資料結構:快速排序程式碼(已優化)

窗外蟋蟀發表於2019-01-22

上一篇部落格中已經討論過關於快速排序如何優化的問題,這次就直接貼出完整已優化的程式碼。此程式碼優化步驟包括了三數取中選取樞軸+小陣列使用插排+三向切分。

完整程式碼:

#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];
    	}
    }
}
複製程式碼

執行結果為:

資料結構:快速排序程式碼(已優化)

相關文章