首页 > 代码库 > 算法(第4版)-2.3 快速排序

算法(第4版)-2.3 快速排序

技术分享
public class Quick {
    public static void sort(Comparable[] a) {
        StdRandom.shuffle(a);                    // 消除对输入的依赖
        sort(a, 0, a.length - 1);
    }

    private static void sort(Comparable[] a, int lo, int hi) {
        if (hi <= lo)    return;
        int j = partition(a, lo, hi);    // 切分
        sort(a, lo, j - 1);                        // 将左半部分a[lo..j-1]排序
        sort(a, j + 1, hi);                        // 将右半部分a[j+1..hi]排序
    }

    private static int partition(Comparable[] a, int lo, int hi) {
        // 将数组切分为a[lo..i-1],a[i],a[i+1..hi]
        int i = lo, j = hi + 1;                // 左右扫描指针
        Comparable v = a[lo];                    // 切分元素
        while (true) {
            // 扫描左右,检查扫描是否结束并交换元素
            while (less(a[++i], v))    if (i == hi)    break;
            while (less(v, a[--j]))    if (j == lo)    break;
            if (i >= j)    break;
            exch(a, i, j);
        }
        exch(a, lo, j);    // 将v = a[j]放入正确的位置
        return j;                // a[lo..j-1] <= a[j] <= a[j+1..hi]达成
    }

    private static boolean less(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }

    private static void exch(Comparable[] a, int i, int j) {
        Comparable t = a[i];
        a[i] = a[j];
        a[j] = t;
    }

    private static void show(Comparable[] a) {
        // 在单行中打印数组
        for (int i = 0; i < a.length; i++)
            StdOut.print(a[i] + " ");
        StdOut.println();
    }

    public static boolean isSorted(Comparable[] a) {
        // 测试数组元素是否有序
        for (int i = 1; i < a.length; i++)
            if (less(a[i], a[i - 1]))    return false;
        return true;
    }

    public static void main(String[] args) {
        // 从标准输入读取字符串,将它们排序并输出
        String[] a = In.readStrings();
        sort(a);
        assert isSorted(a);
        show(a);
    }
}
Quick

 

主要优点:

· 实现简单

· 适用于各种不同的输入数据

· 在一般应用中比其他排序算法都要快得多

 

主要缺点:

· 非常脆弱

 

 

2.3.1 基本算法

 

1. 我们就是通过递归的调用切分来排序的。

 

2. 需要注意以下几点:

· 原地切分

· 别越界

· 保持随机性

· 终止循环

· 处理切分元素值有重复的情况

· 终止递归

 

 

2.3.2 性能特点

 

1. 快速排序的最好情况是每次都正好能将数组对半分。

 

2. 将长度为N的无重复数组排序,快速排序平均需要~2NlnN次比较(以及1/6的交换)。

 

3. 快速排序最多需要约n^2/2次比较,但随机打乱数组能够预防这种情况。

 

 

2.3.3 算法改进

 

1. 切换到插入排序

小型数组由插入排序来完成

 

2. 三取样切分

 

3. 熵最优的排序

-> 三向切分的快速排序

技术分享
public class Quick3way {
    public static void sort(Comparable[] a) {
        StdRandom.shuffle(a);                    // 消除对输入的依赖
        sort(a, 0, a.length - 1);
    }

    private static void sort(Comparable[] a, int lo, int hi) {
        if (hi <= lo)    return;
        int lt = lo, i = lo + 1, gt = hi;
        Comparable v = a[lo];
        while (i <= gt) {
            int cmp = a[i].compareTo(v);
            if             (cmp < 0)    exch(a, lt++, i++);
            else if (cmp > 0)    exch(a, i, gt--);
            else                            i++;
        }    // 现在 a[lo..lt-1] < v = a[lt..gt] < a[gt+1..hi]成立
        sort(a, lo, lt - 1);
        sort(a, gt + 1, hi);
    }

    private static boolean less(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }

    private static void exch(Comparable[] a, int i, int j) {
        Comparable t = a[i];
        a[i] = a[j];
        a[j] = t;
    }

    private static void show(Comparable[] a) {
        // 在单行中打印数组
        for (int i = 0; i < a.length; i++)
            StdOut.print(a[i] + " ");
        StdOut.println();
    }

    public static boolean isSorted(Comparable[] a) {
        // 测试数组元素是否有序
        for (int i = 1; i < a.length; i++)
            if (less(a[i], a[i - 1]))    return false;
        return true;
    }

    public static void main(String[] args) {
        // 从标准输入读取字符串,将它们排序并输出
        String[] a = In.readStrings();
        sort(a);
        assert isSorted(a);
        show(a);
    }
}
Quick3way

 

· 对于存在大量重复元素的数组,这种方法比标准的快速排序的效率高得多。

算法(第4版)-2.3 快速排序