快速排序

672 阅读2分钟

今天我们来聊一聊快速排序,快速排序是预先选择数组中的一个数作为基准,实现它左边的数都小于它,右边的数都大于它,可以说是先整体后局部,所以递归代码实现的顺序和归并排序是有些区别的,要注意一下,这在下面代码中有注解解释。快速排序可以进行一个小优化,那就是等于基准数的都放到中间,小于的都在左边,大于的都在右边,下一个递归直接递归大于部分和小于部分,中间等于的部分可以不用再管了。

基准值我们选择的是取数组中相应的排序范围上随机的一个数,在将其以第一个数或者最后一个数进行交换,基于此实现。随机选择是为了使快速排序规避掉原数组顺序不确定的风险,实现算法的时间复杂度是O(N * logN),空间复杂度是O(logN),不稳定。

图像的直观展示如下:

这个动图是每次都以第一个位置为基准的,也就是浅黄色的块。排好之后再次排的时候就是基准值左侧的先排好,再排右侧的。这个图是直接向右走到头大于的不和最后一个值交换,和下面代码的实现有一些区别。下面的代码会从右侧扩充大于区域,进行了一些优化。 快速排序.gif

相关的代码是:

注意:这里是将随机选择的数和相应范围上最后的数进行交换来开始排的,交换的原因是因为排序的时候需要不断扩充小于它的区域和大于它的区域,完成后基准值在交换到等于区域上,以此完成一轮。

    public static void main(String[] args) {
        int[] nums = new int[]{0,4,2,3,5,7,8,2};
        quickSort(nums, 0, nums.length - 1);
        for (int i : nums){
            System.out.println(i);
        }
    }
    public static void quickSort(int[] arr, int L, int R){
        if (L < R){
            //随机选择一个数交换到最后作为基准,这样尽可能规避最差的情况,使整体复杂度达到O(N*logN)
            swap(arr, L + (int)(Math.random() * (R - L + 1)), R);
            //这里返回的是等于上面基准值的区域块的左边界和右边界,之后再排序就不需要考虑这些等于的了,可以稍微加速一下
            //因为算法的原理是先整体后局部,所以要先进行实现基准数的左边都小于它,右边都大于它,所以partition()放到前面
            //不像归并排序,merge()是排在最后的,因为归并排序是先局部后整体
            int[] p = partition(arr, L ,R);
            quickSort(arr, L, p[0] - 1);
            quickSort(arr, p[1] + 1, R);
        }
    }
    public static int[] partition(int[] arr, int L, int R){
        //less表示的是小于区域
        int less = L - 1;
        //more表示的是大于区域
        int more = R;
        while(L < more){
            if(arr[L] < arr[R]){
                //当前值如果小于的话,当前值和小于区域右一位交换,并且小于区域右扩
                swap(arr, ++less, L++);
            }else if (arr[L] > arr[R]){
                //当前值如果大于的话,当前值和大于区域的左边一位交换,并且大于区域左扩,当
                //前位置不加,因为交换过来的数值不知道它的大小
                swap(arr, --more, L);
            }else {
                //如果等于的话,当前值右移
                L++;
            }
        }
        swap(arr, more, R);
        return new int[]{less + 1, more};
    }
    public static void swap(int[] arr, int L, int R){
        int tmp = arr[L];
        arr[L] = arr[R];
        arr[R] = tmp;
    }