快速排序Java实现

package practice;

import edu.princeton.cs.algs4.*;

public class TestMain {
    public static void main(String[] args) {
        int[] a = new int[20];
        for (int i = 0; i < a.length; i++) {
            int temp = (int)(StdRandom.uniform(1, 10));
            a[i] = temp;
        }
        
        for (int i : a) {
            System.out.print(i+" ");
        }
        System.out.println();
        ToSort.sort3Way(a);
        for (int i : a) {
            System.out.print(i+" ");
        }
    }
}

class ToSort{
    private static int[] anx;
    /*
     * 我第一次写出来的快速排序,容易理解,但需要一倍的额外空间,也不快.....
     */
    public static void mySort(int[] a) {
        anx = new int[a.length];
        myQuickSort(a, 0, a.length - 1);
    }
    public static void myQuickSort(int[] a,int lo,int hi) {
        if (lo >= hi) return;
        int m = lo;
        int n = hi;
        int mid = a[lo];
        for (int i = lo + 1; i <= hi; i++) {
            if (a[i] <= mid) anx[m++] = a[i];
            else if (a[i] > mid) anx[n--] = a[i];
        }
        //此处往后m,n相等
        anx[m] = mid;
        for (int i = lo; i <= hi; i++) a[i] = anx[i];
        myQuickSort(a, lo, m - 1);
        myQuickSort(a, n + 1, hi);
    }
    /*
     * 快速排序 时间复杂度O(NlgN)
     */
    public static void sort(int[] a) {
        quickSort(a, 0, a.length - 1);
    }
    public static void quickSort(int[] a,int lo,int hi) {
        if (lo >= hi) return; //如果分到只剩一个元素,或没有元素,则返回
        int n = partition(a, lo, hi); //将数组切分,取一个中值,分成比它小的一部分和比它大的一部分
        quickSort(a, lo, n - 1); //将两部分分别快速排序
        quickSort(a, n + 1, hi);        
    }
    public static int partition(int[] a,int lo,int hi) {
        int mid = a[lo]; //把第一个元素设为中值,先放在最左边不管
        int m = lo;
        int n = hi + 1;
        while (true) {
            while (a[++m] < mid) if(m == hi) break; //从左开始找出一个比mid大的元素
            while (a[--n] > mid)/*if(n == lo) break; 这句没用,但可以让人更容易理解程序*/;//从右开始找出一个比mid小的元素
            if (m >= n) break; //找完了
            exch(a, m, n);
        }
        exch(a, n, lo); //把最左端中值和"比它小的值中最右端的数"换位置,它就到最中间了
        return n;
    }
    /*
     * 三向切分的快速排序,适用于有大量重复元素的数组
     */
    public static void sort3Way(int[] a) {
        quickSort(a, 0, a.length - 1);
    }
    public static void quickSort3Way(int[] a,int lo,int hi) {
        if (lo >= hi) return;
        int mid = a[lo];
        int lt = lo + 1;
        int gt = hi;
        int i = lo + 1;
        while (i <= gt) { //将比中值小的放在最左端,比中值大的放在最右端,和中值相等的放在中间
            if (a[i] < mid) exch(a, lt++, i++); //换过来的值还是与中值相等的值,所以不用动
            else if (a[i] > mid) exch(a, gt--, i); //换过来的值不知道是什么值,所以还要处理
            else if (a[i] == mid) i++; //相等就过
        }
        exch(a, lo, lt - 1); //把最左端中值和"比它小的值中最右端的数"换位置
        quickSort3Way(a, lo, lt - 2); //调用自己处理剩下的两部分
        quickSort3Way(a, gt + 1, hi);        
    }
    /*
     * 交换a[i]与a[j]的值
     */
    private static void exch(int[] a, int i, int j) {
        int t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
}

快速排序示意图(图片来自《算法(第四版官网)》)

三向切分的快速排序示意图(图片来自《算法(第四版官网)》)

posted @ 2017-07-27 14:07  zhangqi66  阅读(154)  评论(0编辑  收藏  举报