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

普通快速排序

找一个基准值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
    }
}

  

时间: 2024-08-03 02:40:11

快速排序及优化(Java实现)的相关文章

快速排序的优化(一)随机化快速排序

这周研究快速排序优化策略,首先是利用随机化对快速排序进行优化. 众所周知,之前的基础快速排序算法,其效率一个关键点就在与划分元素的选取,由于之前一直选取的是第一个元素,所以当遇到特殊输入,比如太大或者太小,就会造成区间划分极度不合理. 引入随机化,就是在每一次划分的时候随机选取一个元素作为关键字,用它来进行划分.由于每一次划分都是随机选取,所以每一次都选到不好的元素概率低,可以作为一个优化的方向. 和之前的基础快速排序主要区别有两个 1.首先是partition部分 利用rand产生随机数  ,

温故知新,基础复习(快速排序及优化)

温故知新,基础复习(快速排序及优化) 使用了三值取中和插排优化 #include<stdio.h> #define InsertSortNumber 10 void InsertSort(int Arra[],unsigned int LowIndex,unsigned int HighIndex) { printf("low=%d,high=%d\n",LowIndex,HighIndex); for (unsigned int i = LowIndex + 1; i &

如何优化Java垃圾回收-zz

为什么需要优化GC 或者说的更确切一些,对于基于Java的服务,是否有必要优化GC?应该说,对于所有的基于Java的服务,并不总是需要进行GC优化,但前提是所运行的基于Java的系统,包含了如下参数或行为: 已经通过 -Xms 和–Xmx 设置了内存大小 包含了 -server 参数 系统中没有超时日志等错误日志 换句话说,如果你没有设定内存的大小,并且系统充斥着大量的超时日志时,你就需要在你的系统中进行GC优化了. 但是,你需要时刻铭记一条:GC优化永远是最后一项任务. 你应该考虑一下进行GC

算法整理(四):浅析快速排序的优化问题

前文介绍了快速排序的单边扫描和双边扫描,但么有做对比,今天来简单分析下. 一.单边扫描的缺点 单边扫描最大的缺点是每次都要交换,如果一个数组是 5 4 3 2 1,用单边扫描的话,则从4开始,4要和4交换一次,3要和3交换一次,依次类推,这种无意义的操作.正因此用双边扫描会更好,第一趟只需交换一次,就能得到1 4 3 2 5这样的数组.但双边扫描也是可以进一步优化的. 二.双边扫描的优化 优化一:对key值得选取应该使用随机选取的原则,而非第一个数字.意义大家都懂得. 优化二:前文的方法是挖坑法

优化 Java 代码

本文来自:CSDN阿里资深工程师教你如何优化java代码 方便记忆,做了代码 格式化处理.作色高亮. 正文: 一.让代码性能更高 1.需要 Map 的主键和取值时,应该迭代 entrySet 当循环中只需要 Map 的主键时,迭代 keySet 是正确的.但是,当需要主键和取值时,迭代 entrySet 才是更高效的做法,比先迭代 keySet 后再去 get 取值性能更佳. 反例: Map<String, String> map = ...; for (String key : map.ke

【决战西二旗】|快速排序的优化

1.前言 前面的一篇文章https://www.cnblogs.com/backnullptr/p/11934841.html讲了快速排序的基本概念.核心思想.基础版本代码实现等,让我们对快速排序有了一个充分的认识,但还无法达到面试中对快速排序灵活应对的程度. 快速排序是图领奖得主发明的算法,被誉为20世纪最重要的十大算法之一,快速排序为了可以在多种数据集都有出色的表现,进行了非常多的优化,因此对我们来说要深入理解一种算法的最有效的手段就是不断优化提高性能. 通过本文你将了解到以下内容: 快速排

快速排序及优化(Java版)

快速排序(Quicksort)是对冒泡排序的一种改进.快速排序由C. A. R. Hoare在1962年提出. 一次快速排序详细过程: 选择数组第一个值作为枢轴值. 代码实现: package QuickSort; public class QuickSortRealize { public static void QuickSort(int[] arr){ QSort(arr,0,arr.length-1); } //对顺序表子序列作快速排序 待排序序列的最小下标值low和最大下标值high

快速排序及其优化

public class QuickSort { public static void main(String[] args) { int [] a ={1,2,3,0,9,8,7,6,5,4}; Sort(a,10); for(int k=0;k<a.length ;k++){ System.out.print(a[k]+" "); } } private static void Sort(int[] k,int n) { QSort(k,0,n-1); } private s

三种快速排序以及快速排序的优化

一.  快速排序的基本思想 快速排序使用分治的思想,通过一趟排序将待排序列分割成两部分,其中一部分记录的关键字均比另一部分记录的关键字小.之后分别对这两部分记录继续进行排序,以达到整个序列有序的目的. 二.  快速排序的三个步骤 1) 选择基准:在待排序列中,按照某种方式挑出一个元素,作为 "基准"(pivot): 2) 分割操作:以该基准在序列中的实际位置,把序列分成两个子序列.此时,在基准左边的元素都比该基准小,在基准右边的元素都比基准大: 3) 递归地对两个序列进行快速排序,直到