快速排序基本操作的優化(完整程式碼)
阿新 • • 發佈:2019-02-01
這裡是快速排序的優化版,在其中的幾個部分進行了優化。
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);
}