1. 程式人生 > >希爾排序與快速排序

希爾排序與快速排序

上節講的歸併排序執行速度比簡單排序塊,但是它需要的空間是原始陣列空間的兩倍;通常這是一個嚴重的缺點
        希爾排序,希爾排序的時間複雜度是O(N*(logN)^2)。希爾排序是基於插入排序的。希爾排序又叫縮小增量排序,它是基於插入排序的增強版。
        基本思想:把記錄按步長進行分組,對每組記錄採用直接插入的方法進行排序。隨著步長的縮小,所分成的組包含的記錄就越來越多,當步長的值減小到1時
,整個資料合成一組,構成一組有序的記錄,則完成排序。
        過程如下圖所示:
http://images2015.cnblogs.com/blog/318837/201604/318837-20160422102024757-37862627.png
        具體的執行步驟是:
        1,在第一趟排序過程中,我們不妨設gap1=N/2=5,即為相隔距離為5的元素組成一組,可以分為5組。接下來,按照直接插入排序的方法對每個組進行排序。
        2,第二趟排序中,我們把上次的gap縮小一半,即為gap2=gap1/2=2(取整數)。這樣每相隔距離為2的元素組成一組,可以分為2組。按照直接插入排序的方法
對每個組進行排序。
        3,在第三趟排序中,再次把gap縮小一半,即為gap3=gap2/2=1。這樣相隔距離為1的元素組成一組,即只有一組。按照直接插入排序的演算法對每個組進行排序。此時排序結束。
        注意希爾排序是不穩定的排序。
        核心程式碼:
                public void shellsort(int[] list){
                        int gap=list.length/2;
                        while(gap>=1){
                                for(int i=gap;i<list.length;i++){
                                        int j=i-gap;
                                        int temp=list[i];
                                        if(j>=0&&list[j]>temp){
                                                list[i]=list[j];
                                                list[j]=temp;
                                        }
                                }
                                gap=gap/2;
                        }
                        printAll(list);
                } 

毫無疑問,快速排序是最流行的排序演算法,大多是情況下,快速排序都是最快的,執行時間是O(N*logN)級別。它是一種既不浪費空間也不浪費時間的排序演算法。
        方法其實很簡單:給一個序列“6 1 2 7 9 3 4 5 10 8”兩端開始“探測”。以第一個數作為基準數(6),先從右向左找一個小於6的數,再從左向右找一個大於6的數,然後交換他們。這裡可以用兩個變數i和j,分別指向最左邊和最右邊。我們為這兩個變數起一個好聽的名字“哨兵i”和“哨兵j”。剛開始的時候讓哨兵i指向>序列的最左邊(即為i=0),指向數字6.讓哨兵j指向序列的最右邊(即為i=9),指向數字8.如圖:

        首先哨兵j開始出動。因為此處設定的基準數是最左邊的數,所以需要讓哨兵j先出動,這一點非常重要。哨兵j一步一步的向左挪動(即為j--),直到找到一個小於6的數停下來。接下來哨兵i再一步一步向右挪動(即為i++),直到找到一個大於6的數停下來。最後哨兵j停在了數字5面前,哨兵i停在了數字7面前。如圖:


        現在交換哨兵i和哨兵j所指向的元素的值,交換後的序列如下:
        6 1 2 5 9 3 4 7 10 8
        到此,第一次交換結束。接下來開始哨兵j繼續向左挪動(注意,每次必須數哨兵j先出發)。他發現了4(比基準數6要小,滿足要求)之後停了下來。哨兵i也繼續向右挪動,他發現了9(比基準數6大,滿足要求)之後停了下來。如下圖:


        此時再次進行交換,交換之後的序列如下:
        6 1 2 5 4 3 9 7 10 8
        第二次交換結束後,“探測”繼續。哨兵j繼續向左挪動,他發現了3(比基準數6小,滿足要求)之後停了下來。哨兵i繼續向右挪動,糟糕!此時哨兵i和哨兵
j相遇,哨兵i和哨兵j都走到了3面前。說明此時“探測”結束。我們將基準數6和3進行交換。如下圖:


        交換後的序列如下:
        3 1 2 5 4 6 9 7 10 8

        此時,第一輪“探測結束”。此時以基準數6為分界點,6左邊的數小雨等於6,6右邊的數大於等於6.
        將以6為分界點的兩個子序列:3 1 2 5 4和9 7 10 8再次進行快速排序.整個圖的處理過程如下圖所示:

        注意:快速排序的最差時間複雜度為O(N^2),它的平均複雜度為O(NlogN),它是基於“二分”的思想。

        程式碼實現:

        public void quicksort(int[] n,int left,int right){
                int dp;
                if(left<=right){
                        dp=partion(n,left,right);
                        quicksort(n,left,dp-1);
                        quicksort(n,dp+1,right);
                }
        }
        public void partion(int[] n,int left,int right){
                int pro=n[left];
                int start=left;
                int temp=0;
                while(left<right){
                        while(left<right&&n[right]>=pro){
                                right--;
                        }
                        if(left<right){
                                temp=n[right];
                        }
                        while(left<right&&n[left]<=pro){
                                left++;
                        }
                        if(left<right){
                                n[right--]=n[left]
                                n[left++]=temp
                        }
                }
                n[start]=n[left];
                n[left]=pro;
                return left;
        }
轉載自:靜默虛空 坐在馬桶上看演算法:快速排序