你還記得快速排序嗎?

寫個快速排序看看:java

public static void sort(int[] a, int low, int high)
{
    int i,j,t,temp;
    if(low>high) {
        return;
    }
    temp=a[low]; //基準
    i=low;
    j=high;
    while(i!=j)
    {
        while(a[j]>=temp && i<j)//順序很重要
        {
            j--;
        }
        while(a[i]<=temp && i<j) {
            i++;
        }
        if(i<j)
        {
            t=a[i];
            a[i]=a[j];
            a[j]=t;
        }
    }//再把基準數進行交換  
    a[low]=a[i];
    a[i]=temp;
    sort(a,low,i-1);//遞歸
    sort(a,i+1,high);
}

快速排序使用分治的思想,經過一趟排序將待排序列分割成兩部分,其中一部分記錄的關鍵字均比另外一部分記錄的關鍵字小,另外一部分比基準點。以後分別對這兩部分記錄繼續進行排序,以達到整個序列有序的目的。數組

準備數據測一下:函數

int[] array = {12,21,15,16,15,1,36,40,3,9,66,9,34,25,77,7,2,56,-15,56,-3,69};
        System.out.print("待排序:");
        for (int aa:array ) {
            System.out.print(aa + " ");
        }
        System.out.println("");
        int start = 0;
        int end = array.length-1;
        sort(array,start,end);
//        sort2(array,start,end);
        System.out.print("排序完:");
        for (int a:array) {
            System.out.print(a + " ");
        }

排序的結果:性能

上面的操做是從右往左找到比基準小的,從左往右找到比基準大的,而後交換,最後交換基準位置。優化

還看到一種操做套路是把基準交換來換去,最後的效果也是同樣的。我是以爲第一種好一點,沒有那麼多交換操做排序

public static void sort2(int[] a, int low, int high){
    int start = low;
    int end = high;
    int key = a[low];


    while(end>start){
        //從後往前比較
        while(end>start&&a[end]>=key)
        {
            end--;
        }
        if(a[end]<key){
            int temp = a[end];
            a[end] = a[start];
            a[start] = temp;
        }
        //從前日後比較
        while(end>start&&a[start]<=key)
        {
            start++;
        }
        if(a[start]>key){
            int temp = a[start];
            a[start] = a[end];
            a[end] = temp;
        }
    }
    //遞歸
    if(start>low) {
        sort2(a, low, start - 1);
    }
    if(end<high) {
        sort2(a, end + 1, high);
    }
}

這邊的選擇基準點就是選第一個數據,若是在數據基本有序的狀況下,你選擇第一個數據是比較糟糕的,因此若是針對的都是這樣的數據,那麼能夠考慮選擇隨機的位置做爲基準點,總不至於那麼倒黴吧,固然糟糕的時候仍是糟糕的,你懂我說的糟糕的時間的複雜度。遞歸

最佳的劃分是將待排序的序列分紅等長的子序列,最佳的狀態咱們可使用序列的中間的值。咱們但是學過中位數的數,前人們總結了一個隨機取三數(隨機也能夠直接取左邊,右邊,和中間,由於反正數據是隨機的,再弄一個隨機也不必),而後取中位數做爲基準,至少避開了那種最倒黴的狀況哈哈。咱們這邊只是取了三個數,若是加大樣本的數據,是方便了和加快了排序,可是前期就花了很多時間,具體仍是要根據排序數據規模來處理,並非放之四海皆準。編譯器

還有前輩們說對於很小和部分有序的數組,快排不如插排好。當待排序序列的長度分割到必定大小後,繼續分割的效率比插入排序要差,此時可使用插排而不是快排。我還不知道怎麼分析出來的,可是這樣有個地方,看排序的後面有個遞歸,若是待排序的序列劃分極端不平衡,遞歸的深度將趨近於n,而棧的大小是頗有限的,每次遞歸調用都會耗費必定的棧空間,函數的參數越多,每次遞歸耗費的空間也越多。因此這邊還能夠改爲尾遞歸,優化後,能夠縮減堆棧深度,聽說能夠由原來的O(n)縮減爲O(logn),將會提升性能,可是用java寫,說是編譯器沒對尾遞歸這種作過多的優化,因此......編譯

相關文章
相關標籤/搜索