1. 程式人生 > >Arrays.sort()用的是什麼排序演算法?怎麼優化?

Arrays.sort()用的是什麼排序演算法?怎麼優化?

Arrays.sort()用的是快速排序演算法。相信大家對於這個都是瞭解的。
演算法的思想:
選擇基準將陣列一分為二,基準前面的比基準小,基準後面的比基準大,之後分別對這兩部分繼續之前的操作,已達到整個陣列有序的目的。
演算法內容描述:
先選擇一個基準,指向陣列開始的指標start和指向陣列結束的指標end;
當start小於end的時候,如果基準的值小於end指向陣列的值時,end往前移動;
當基準的值不在小於end指向陣列的值的時候,交換兩個指標指向的陣列的值;
然後當基準的值大於start指向陣列的值的時候,start往後移動;


當基準的值不大於start指向陣列的值的時候,交換兩個指標指向的陣列的值;
返回基準的位置並進行遞迴操作完成排序。

程式碼如下:

public class Test2 {

    public static void swap(int[] arr, int j, int i){

        int temp = arr[j];
        arr[j] = arr[i];
        arr[i] = temp;
    }

    public static int partition(int arr[], int start, int
end){ assert(null != arr); int temp = arr[start]; while(start < end){ while(temp < arr[end] && start < end){ end--; } swap(arr, start, end); while(temp > arr[start] && start < end){ start++; } swap(arr, start, end); } System.out
.println(Arrays.toString(arr) + " " + start); return start; } public static void partitionSort(int arr[], int start, int end){ assert(null != arr); if(start < end){ int midd = partition(arr, start, end); partitionSort(arr, start, midd - 1); partitionSort(arr, midd + 1, end); } } public static void main(String[] args) { int arr[] = {9,1,5,8,3,7,4,6,2}; Test2.partitionSort(arr, 0, arr.length - 1); System.out.println(Arrays.toString(arr)); } }

執行結果:
[2, 1, 5, 8, 3, 7, 4, 6, 9] 8
[1, 2, 5, 8, 3, 7, 4, 6, 9] 1
[1, 2, 4, 3, 5, 7, 8, 6, 9] 4
[1, 2, 3, 4, 5, 7, 8, 6, 9] 3
[1, 2, 3, 4, 5, 6, 7, 8, 9] 6
[1, 2, 3, 4, 5, 6, 7, 8, 9]

快速排序的優化:
①優化基準的選擇
上面的程式選擇的基準是陣列起始位置,但是跟明顯,我們並沒有達到想要的理想結果將陣列劃分為兩部分,進行遞迴操作;
所以就有了三數取中法來選取基準,即取三個關鍵字先進行排序,將中間數作為基準,一般去開始,結束,和中間;
當然也可以隨機選取;其實還有一種九數取中法,這裡就不詳細介紹了,有興趣的可以自己瞭解一下。
下面是三數取中法的程式碼:

public void medianOfThree(int[] arr, int start, int end){

        int m = start + (end - start) / 2;
        if(arr[start] > arr[end]){
            swap(arr, start, end);
        }
        if(arr[m] > arr[end]){
            swap(arr, end, m);
        }
        if(arr[m] > arr[start]){
            swap(arr, m, start);
        }
    }

②優化不必要的交換
首先我們通過上面的程式碼很容易發現在交換的過程中,有許多部分是沒必要交換的,於是我們通過賦值替代交換來省去沒必要的交換;

程式碼如下:

public int partition3(int arr[], int start, int end){
        assert(null != arr);

        medianOfThree(arr, start, end);
        int temp = arr[start];

        while(start < end){
            while(temp < arr[end] && start < end){
                end--;
            }
            arr[start] = arr[end];
            while(temp > arr[start] && start < end){
                start++;
            }
            arr[end] = arr[start];
        }
        arr[start] = temp;
        System.out.println(Arrays.toString(arr) + "   " +  start);
        return start;
    }

③優化小陣列時的排序方案
一般對於小陣列排序,我們需要選擇插入排序,因為插入排序是簡單排序效能最高的。所以我們做如下修改:

public void partitionSort4(int arr[], int start, int end){
        assert(null != arr);

        if((end - start) > INSERT_SORT){
            int midd = partition3(arr, start, end);
            partitionSort3(arr, start, midd - 1);
            partitionSort3(arr, midd + 1, end);
        }else{
            insertSort(arr);
        }
    }

其中,INSERT_SORT選擇的大小眾說紛紜,自我覺得在海量資料面前,選擇20跟選擇7沒有太大的差異吧。(這話如果有誤,望大家批評指正)
④優化遞迴操作
我們都知道遞迴的額外花銷還是很大的,減少遞迴可以大大提高效能,故此做如下修改:

 public void partitionSort5(int arr[], int start, int end){
        assert(null != arr);
        int midd;
        if((end - start) > INSERT_SORT){
            while(start < end){
                midd = partition3(arr, start, end);
                partitionSort5(arr, start, midd - 1);
                start = midd + 1;
            }
        }else{
            insertSort(arr);
        }
    }

以上全是本人自己對於快速排序的總結,如果有什麼不恰當或者錯誤的地方,還望各位批評指正!