快速排序實現之遞歸與非遞歸


一、算法思想:

   快速排序是C.R.A.Hoare於1962年提出的一種划分交換排序。它采用了一種分治的策略,通常稱其為分治法(Divide-and-ConquerMethod)。設當前待排序的無序區為R[low..high],利用分治法可將快速排序的基本思想描述為:在R[low..high]中任選一個記錄作為基准(Pivot),以此基准將當前無序區划分為左、右兩個較小的子區間R[low..pivotpos-1)和R[pivotpos+1..high],並使左邊子區間中所有記錄的關鍵字均小於等於基准記錄(不妨記為pivot)的關鍵字pivot.key,右邊的子區間中所有記錄的關鍵字均大於等於pivot.key,而基准記錄pivot則位於正確的位置(pivotpos)上。通過遞歸調用快速排序對左、右子區間R[low..pivotpos-1]和R[pivotpos+1..high]快速排序。

二、算法實現:

1、遞歸實現:

    private static void rec_quickSort(int[] a, int start, int end) {
        int index = 0;
        if(start < end) {
            index = partition(a,start,end);
            rec_quickSort(a,start,index-1);
            rec_quickSort(a,index+1,end);
        }
    }

    private static int partition(int[] a, int start, int end) {
        int pivot = a[start];
        while(start < end) {
            while(start < end && a[end] >= pivot)
                end--;
            a[start] = a[end];
            while(start < end && a[start] <= pivot)
                start++;
            a[end] = a[start];
        }
        a[start] = pivot;
        return start;
    }

2、非遞歸實現:

    private static void nonRec_quickSort(int[] a,int start,int end) {
        LinkedList<Integer> stack = new LinkedList<Integer>();  //用棧模擬
        if(start < end) {
            stack.push(end);
            stack.push(start);
            while(!stack.isEmpty()) {
                int l = stack.pop();
                int r = stack.pop();
                int index = partition(a, l, r);
                if(l < index - 1) {
                    stack.push(index-1);
                    stack.push(l);
                }
                if(r > index + 1) {
                    stack.push(r);
                    stack.push(index+1);
                }
            }
        }
    }
    
    private static int partition(int[] a, int start, int end) {
        int pivot = a[start];
        while(start < end) {
            while(start < end && a[end] >= pivot)
                end--;
            a[start] = a[end];
            while(start < end && a[start] <= pivot)
                start++;
            a[end] = a[start];
        }
        a[start] = pivot;
        return start;
    }

 

三、算法分析:

快速排序的時間主要耗費在划分操作上,對長度為k的區間進行划分,共需k-1次關鍵字的比較。

1、最壞時間復雜度

最壞情況是每次划分選取的基准都是當前無序區中關鍵字最小(或最大)的記錄,划分的結果是基准左邊的子區間為空(或右邊的子區間為空),而划分所得的另一個非空的子區間中記錄數目,僅僅比划分前的無序區中記錄個數減少一個。因此,快速排序必須做n-1次划分,第i次划分開始時區間長度為n-i+1,所需的比較次數為n-i(1≤i≤n-1),故總的比較次數達到最大值:C max= n(n-1)/2=O(n 2)

2、最好時間復雜度

在最好情況下,每次划分所取的基准都是當前無序區的"中值"記錄,划分的結果是基准的左、右兩個無序子區間的長度大致相等。總的關鍵字比較次數:0(nlgn)
注意:用遞歸樹來分析最好情況下的比較次數更簡單。因為每次划分后左、右子區間長度大致相等,故遞歸樹的高度為O(lgn),而遞歸樹每一層上各結點所對應的划分過程中所需要的關鍵字比較次數總和不超過n,故整個排序過程所需要的關鍵字比較總次數C(n)=O(nlgn)。
因為快速排序的記錄移動次數不大於比較的次數,所以快速排序的最壞時間復雜度應為0(n 2),最好時間復雜度為O(nlgn)。

3、空間復雜度

快速排序在 系統內部需要一個棧來實現遞歸。若每次划分較為均勻,則其遞歸樹的高度為O(lgn),故遞歸后需棧空間為O(lgn)。最壞情況下,遞歸樹的高度為O(n),所需的棧空間為O(n)。

4、穩定性

快速排序是非穩定的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM