快速排序算法(Java)

一,快速排序

快速排序,是實踐中的一種快速的排序算法,在C++和java基本類型的排序中特別有用,它的平均運行時間是O(NlogN)。該算法之因此特別快,主要是因爲很是精煉和高度優化的內部循環。它的最壞情形性能爲O(N²),但通過少量努力可以使這種情形極難出現,經過將快速排序和堆排序結合,因爲堆排序的O(NlogN)最壞情形運行時間,咱們能夠對幾乎全部的輸入都能達到快速排序的快速運行時間。java

二,分割策略

此處描述的分割策略已經被證實可以給出好的結果,咱們將會看到,分割是一種很容易出錯或者低效的操做,但使用一種已知方法是安全的。該法的第一步是經過將樞紐元(錨點)與最後的元素交換使得樞紐元離開要被分割的數據段。i從第一個元素開始而j從倒數第二個元素開始,若是原始輸入與前面的同樣,那麼下面的圖表示當前的狀態(6是樞紐元)
圖中6是樞紐元
暫時假設全部元素互異,後面咱們將着重考慮在出現重複元素時該怎麼辦,做爲有限的狀況,若是全部的元素都相同,那麼咱們的算法必須作該作的事。web

在分割階段,咱們要作的就是將全部小元素必定到樞紐元的左邊而把大的元素移動到它的右側。算法

當i在j的左邊的時候,咱們將i右移,移過哪些小於樞紐元的元素,並將j左移,移過哪些大於樞紐元的元素。當i,j中止的時候,i指向一個大元素而j指向一個小元素,若是i在j的左邊,那麼將兩個元素互換,其效果是吧一個大元素推向右邊,而將一個小元素推向左邊,在上圖的例子中,i不移動,而j劃過一個位置,狀況以下圖
這裏寫圖片描述
這裏寫圖片描述數組

在最後一步當樞紐元與i所指向的元素交換的時候,咱們知道在位置p小於i的每個元素都必然是小元素,這是由於或者位置P包含一個從它開始移動的小元素或者位置P上原來的大元素在交換期間被置換了,相似的論斷指出,在位置p>i上的元素必然都是大元素。安全

三,小數組

對於很小的數組(N<=20),快速排序不如插入排序。不只如此,由於快速排序是遞歸的,因此這樣的情形常常發生,一般的解決方法是對於小的數組不使用遞歸的快速排序,而代之以諸如插入排序這樣的對小數組更有效的排序算法,使用這種策略實際上能夠節省大約15%的運行時間。一種好的截止範圍是N=10,雖然在5到20之間任一截止範圍均可能產生相似結果,這種作法也避免了一些有害的退化情形。數據結構

四,實際的快速排序例程

如下例程來自於《數據結構和算法分析java第三版》數據結構和算法

package com.xp.java.sort;

import java.util.Arrays;

/** * @類描述:快速排序 * @建立人:Wangxp */
public class QuickSort {
    private static final int CUTOFF = 3;

    /** * Quicksort algorithm. * * @param a an array of Comparable items. */
    public static <AnyType extends Comparable<? super AnyType>> void quicksort(AnyType[] a) {
        quicksort(a, 0, a.length - 1);
    }

    /** * Internal quicksort method that makes recursive calls. * Uses median-of-three partitioning and a cutoff of 10. * * @param a an array of Comparable items. * @param left the left-most index of the subarray. * @param right the right-most index of the subarray. */
    private static <AnyType extends Comparable<? super AnyType>> void quicksort(AnyType[] a, int left, int right) {
        if (left + CUTOFF <= right) {
            AnyType pivot = median3(a, left, right);

            // Begin partitioning
            int i = left, j = right - 1;
            for (; ; ) {
                while (a[++i].compareTo(pivot) < 0) {
                }
                while (a[--j].compareTo(pivot) > 0) {
                }
                if (i < j)
                    swapReferences(a, i, j);
                else
                    break;
            }

            swapReferences(a, i, right - 1);   // Restore pivot

            quicksort(a, left, i - 1);    // Sort small elements
            quicksort(a, i + 1, right);   // Sort large elements
        } else  // Do an insertion sort on the subarray
            insertionSort(a, left, right);
    }

    /** * Method to swap to elements in an array. * * @param a an array of objects. * @param index1 the index of the first object. * @param index2 the index of the second object. */
    public static <AnyType> void swapReferences(AnyType[] a, int index1, int index2) {
        AnyType tmp = a[index1];
        a[index1] = a[index2];
        a[index2] = tmp;
    }

    /** * Return median of left, center, and right. * Order these and hide the pivot. */
    private static <AnyType extends Comparable<? super AnyType>> AnyType median3(AnyType[] a, int left, int right) {
        int center = (left + right) / 2;
        if (a[center].compareTo(a[left]) < 0)
            swapReferences(a, left, center);
        if (a[right].compareTo(a[left]) < 0)
            swapReferences(a, left, right);
        if (a[right].compareTo(a[center]) < 0)
            swapReferences(a, center, right);

        // Place pivot at position right - 1
        swapReferences(a, center, right - 1);
        return a[right - 1];
    }

    /** * Internal insertion sort routine for subarrays * that is used by quicksort. * * @param a an array of Comparable items. * @param left the left-most index of the subarray. * @param right the right-most index of the subarray. */
    private static <AnyType extends Comparable<? super AnyType>> void insertionSort(AnyType[] a, int left, int right) {
        for (int p = left + 1; p <= right; p++) {
            AnyType tmp = a[p];
            int j;
            for (j = p; j > left && tmp.compareTo(a[j - 1]) < 0; j--)
                a[j] = a[j - 1];
            a[j] = tmp;
        }
    }

    public static void main(String[] args) {
        Integer[] array = new Integer[]{34, 8, 64, 51, 32, 21};
        quicksort(array);
        System.out.println(Arrays.toString(array));
    }
}

五,快速排序的分析

這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述

六,小結

下面給出快速排序的另外一種便於理解的寫法ide

//下面是另一種寫法
    public static void quickSort(int[] a) {
        if (a.length > 0) {
            quickSort(a, 0, a.length - 1);
        }
    }

    private static void quickSort(int[] a, int low, int high) {
        //1,找到遞歸算法的出口
        if (low > high) {
            return;
        }
        //2, 存
        int i = low;
        int j = high;
        //3,key
        int key = a[low];
        //4,完成一趟排序
        while (i < j) {
            //4.1 ,從右往左找到第一個小於key的數
            while (i < j && a[j] > key) {
                j--;
            }
            // 4.2 從左往右找到第一個大於key的數
            while (i < j && a[i] <= key) {
                i++;
            }
            //4.3 交換
            if (i < j) {
                int p = a[i];
                a[i] = a[j];
                a[j] = p;
            }
        }
        // 4.4,調整key的位置
        int p = a[i];
        a[i] = a[low];
        a[low] = p;
        //5, 對key左邊的數快排
        quickSort(a, low, i - 1);
        //6, 對key右邊的數快排
        quickSort(a, i + 1, high);
    }

對於快速排序的理解,建議可使用上面的代碼進行斷電調試一步一步看交換的過程。更容易理解快速排序。svg

另外一篇:插入排序(java)
本篇中分析部分出自《數據結構與算法分析-java語言結構第三版》性能