快速排序是每次选择锚点,然后将比锚点小的数放到锚点的左边,大的数放到右边。然后递归将锚点左边的数,继续选择锚点,比锚点小的数放到锚点的左边,大的数放到右边。同理递归锚点右边的数。直至剩下一个数为止。
由于锚点的选择会影响快速排序的效率,最差情况下,假如锚点左边没有数,那么锚点右边就是整个数组,这样情况下时间复杂度为n*n。
为了避免这种情况,我们选择数组中first,mid,last的中位数作为锚点,并将这三个数排序。那么锚点首先放置到last-1的位置。当左边数大于锚点,右边数小于锚点,便交换两个数,直至左边数的角标大于右边。结束之后,将锚点放到大于左边小于右边的位置。
由于对于数组元素个数较小情况下,直接插入效率比快速排序高,那么我们对快速排序进一步优化,数目小时,我们选择直接插入排序。
private static void quickSort(int[] a) {
qSort(a,0,a.length - 1);
}
private static void qSort(int[] a, int low, int high) {
if(high - low + 1 < MIN_SIZE){
insertSort(a, low, high);
}else{
int pivot = partition(a,low,high);
qSort(a, low, pivot - 1);
qSort(a, pivot + 1, high);
}
}
private static void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
private static int partition(int[] a, int low, int high) {
int middle = (high + low)/2;
sortFirstMidLast(a,low,middle,high);
swap(a,middle , high - 1);
int pivot = high - 1;
int left = low + 1;
int right = high - 2;
boolean done = false;
while(!done){
while(a[left] < a[pivot]){
left ++;
}
while(a[right] > a[pivot]){
right --;
}
if(left < right){
swap(a, left, right);
left ++;
right --;
}else{
done = true;
}
}
swap(a, left, pivot);
pivot = left;
return pivot;
}
private static void sortFirstMidLast(int[] a, int low, int middle ,int high) {
order(a,low,middle);
order(a, middle, high);
order(a, low, middle);
}
private static void order(int[] a, int i, int j) {
if(a[i] > a[j]){
swap(a, i, j);
}
}
private static void insertSort(int[] a,int low,int high){
int temp,i,j;
for (i = low + 1; i <= high; i++) {
if(a[i] < a[i-1]){
temp = a[i];
for (j = i-1; j >= low && temp < a[j]; j--) {
a[j+1] = a[j];
}
a[j+1] = temp;
}
}
}