码迷,mamicode.com
首页 > 编程语言 > 详细

快速排序及优化(Java实现)

时间:2017-11-29 20:50:24      阅读:241      评论:0      收藏:0      [点我收藏+]

标签:rand   str   ati   不一致   math   com   ret   lin   实现   

普通快速排序

找一个基准值base,然后一趟排序后让base左边的数都小于base,base右边的数都大于等于base。再分为两个子数组的排序。如此递归下去。

public class QuickSort {

    public static <T extends Comparable<? super T>> void sort(T[] arr) {
        sort(arr, 0, arr.length - 1);
    }

    public static <T extends Comparable<? super T>> void sort(T[] arr, int left, int right) {
        if (left >= right) return;
        int p = partition(arr, left, right);
        sort(arr, left, p - 1);
        sort(arr, p + 1, right);
    }

    private static <T extends Comparable<? super T>> int partition(T[] arr, int left, int right) {
        T base = arr[left];
        int j = left;
        for (int i = left + 1; i <= right; i++) {
            if (base.compareTo(arr[i]) > 0) {
                j++;
                swap(arr, j, i);
            }
        }
        swap(arr, left, j);
        return j;//返回一躺排序后基准值的下角标
    }

    public static void swap(Object[] arr, int i, int j) {
        if (i != j) {
            Object temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }

    private static void printArr(Object[] arr) {
        for (Object o : arr) {
            System.out.print(o);
            System.out.print("\t");
        }
        System.out.println();
    }

    public static void main(String args[]) {
        Integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6};
        printArr(arr);//3   5   1   7   2   9   8   0   4   6
        sort(arr);
        printArr(arr);//0   1   2   3   4   5   6   7   8   9
    }
}

  

快速排序优化:

在数组几乎有序时,快排性能不好(因为每趟排序后,左右两个子递归规模相差悬殊,大的那部分最后很可能会达到O(n^2))。

解决:基准值随机地选取,而不是每次都取第一个数。这样就不会受“几乎有序的数组”的干扰了。但是对“几乎乱序的数组”的排序性能可能会稍微下降,至少多了排序前交换的那部分,乱序时这个交换没有意义...有很多“运气”成分..

public class QuickSort {

    public static <T extends Comparable<? super T>> void sort(T[] arr) {
        sort(arr, 0, arr.length - 1);
    }

    public static <T extends Comparable<? super T>> void sort(T[] arr, int left, int right) {
        if (left >= right) return;
        int p = partition(arr, left, right);
        sort(arr, left, p - 1);
        sort(arr, p + 1, right);
    }

    private static <T extends Comparable<? super T>> int partition(T[] arr, int left, int right) {
        //排序前,先让基准值和随机的一个数进行交换。这样,基准值就有随机性。
        //就不至于在数组相对有序时,导致左右两边的递归规模不一致,产生最坏时间复杂度
        swap(arr,left,(int)(Math.random()*(right - left + 1)+left));

        T base = arr[left];
        int j = left;
        for (int i = left + 1; i <= right; i++) {
            if (base.compareTo(arr[i]) > 0) {
                j++;
                swap(arr, j, i);
            }
        }
        swap(arr, left, j);
        return j;//返回一躺排序后,基准值的下角标
    }

    public static void swap(Object[] arr, int i, int j) {
        if (i != j) {
            Object temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }

    private static void printArr(Object[] arr) {
        for (Object o : arr) {
            System.out.print(o);
            System.out.print("\t");
        }
        System.out.println();
    }

    public static void main(String args[]) {
        Integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6};
        printArr(arr);//3   5   1   7   2   9   8   0   4   6
        sort(arr);
        printArr(arr);//0   1   2   3   4   5   6   7   8   9
    }
}

  

快速排序继续优化:

快排是不断减小问题规模来解决子问题的,需要不断递归。但是递归到规模足够小时,如果继续采用这种 不稳定+递归 的方式执行下去,效率不见得会很好。

所以当问题规模较小时,近乎有序时,插入排序表现的很好。Java自带的Arrays.sort()里经常能看到这样的注释:“Use insertion sort on tiny arrays”,“Insertion sort on smallest arrays

public class QuickSort {

    public static <T extends Comparable<? super T>> void sort(T[] arr) {
        sort(arr, 0, arr.length - 1, 16);
    }

    /**
     * @param arr   待排序的数组
     * @param left  左闭
     * @param right 右闭
     * @param k     当快排递归到子问题的规模 <= k 时,采用插入排序优化
     * @param <T>   泛型,待排序可比较类型
     */
    public static <T extends Comparable<? super T>> void sort(T[] arr, int left, int right, int k) {
        // 规模小时采用插入排序
        if (right - left <= k) {
            insertionSort(arr, left, right);
            return;
        }
        int p = partition(arr, left, right);
        sort(arr, left, p - 1, k);
        sort(arr, p + 1, right, k);
    }

    public static <T extends Comparable<? super T>> void insertionSort(T[] arr, int l, int r) {
        for (int i = l + 1; i <= r; i++) {
            T cur = arr[i];
            int j = i - 1;
            for (; j >= 0 && cur.compareTo(arr[j]) < 0; j--) {
                arr[j + 1] = arr[j];
            }
            arr[j + 1] = cur;
        }
    }

    private static <T extends Comparable<? super T>> int partition(T[] arr, int left, int right) {
        //排序前,先让基准值和随机的一个数进行交换。这样,基准值就有随机性。
        //就不至于在数组相对有序时,导致左右两边的递归规模不一致,产生最坏时间复杂度
        swap(arr, left, (int) (Math.random() * (right - left + 1) + left));

        T base = arr[left];
        int j = left;
        for (int i = left + 1; i <= right; i++) {
            if (base.compareTo(arr[i]) > 0) {
                j++;
                swap(arr, j, i);
            }
        }
        swap(arr, left, j);
        return j;//返回一躺排序后,基准值的下角标
    }


    public static void swap(Object[] arr, int i, int j) {
        if (i != j) {
            Object temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }

    private static void printArr(Object[] arr) {
        for (Object o : arr) {
            System.out.print(o);
            System.out.print("\t");
        }
        System.out.println();
    }

    public static void main(String args[]) {
        Integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6};
        printArr(arr);//3   5   1   7   2   9   8   0   4   6
        sort(arr);
        printArr(arr);//0   1   2   3   4   5   6   7   8   9
    }
}

  

快速排序及优化(Java实现)

标签:rand   str   ati   不一致   math   com   ret   lin   实现   

原文地址:http://www.cnblogs.com/noKing/p/7922397.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!