java - 快速排序

一、什么是快速排序

快速排序(QuickSort)是一种常用的排序算法,属于交换排序的一种。它的基本思想是通过一趟排序将待排序的记录分割成独立的两部分,其中一部分记录的关键字都比另一部分记录的关键字小,然后分别对这两部分记录继续进行排序,以达到整个序列有序的目的。

快速排序的基本步骤如下:

  1. 选择基准元素: 从待排序序列中选择一个元素作为基准元素。通常选择序列的第一个元素,但也可以随机选择或者选择中间元素。

  2. 分割操作: 将比基准元素小的元素移到基准元素的左边,将比基准元素大的元素移到基准元素的右边。基准元素在这一过程中已经找到了最终的位置,它左边的元素都比它小,右边的元素都比它大。

  3. 递归排序: 对基准元素左右两边的子序列分别进行快速排序,重复以上步骤,直到整个序列有序。

二、代码实现

    public static void swap(int[] nums,int left,int right){
        int tmp = nums[left];
        nums[left] = nums[right];
        nums[right] = tmp;
    }
    public static int partition(int[] nums,int left,int right){
        int i = left;
        int j = right;
        while(i < j){
            while(i < j && nums[j] >= nums[left]){
                j--;
            }
            while(i < j && nums[i] <= nums[left]){
                i++;
            }
            swap(nums,i,j);
        }
        swap(nums,left,i);
        return i;
    }
    public static void quicksort(int[] nums,int left,int right){
        if(left >= right){
            return ;
        }
        int pivot = partition(nums,left,right);
        quicksort(nums,left,pivot-1);
        quicksort(nums,pivot+1,right);
    }

三、算法特性 

时间复杂度:O(n^log n),在平均情况下,哨兵划分的递归层数为 log⁡ n ,每层中的总循环数为 n ,总体使用 O(n^log⁡ n) 时间。在最差情况下,每轮哨兵划分操作都将长度为 n 的数组划分为长度为 0 和 n−1 的两个子数组,此时递归层数达到 n 层,每层中的循环数为 n ,总体使用 O(n^2) 时间。

空间复杂度:O(n),在输入数组完全倒序的情况下,达到最差递归深度 n ,使用 O(n) 栈帧空间。排序操作是在原数组上进行的,未借助额外数组。

非稳定排序: partition方法的最后一步基准数可能会被交换至相等元素的右侧。

四、代码优化

为了进一步改进,我们可以在数组中选取三个候选元素(通常为数组的首、尾、中点元素),并将这三个候选元素的中位数作为基准数。这样一来,基准数“既不太小也不太大”的概率将大幅提升。当然,我们还可以选取更多候选元素,以进一步提高算法的稳健性。采用这种方法后,时间复杂度劣化至 O(n^2) 的概率大大降低。

 public static void swap(int[] nums,int left,int right){
        int tmp = nums[left];
        nums[left] = nums[right];
        nums[right] = tmp;
    }
    public static int medianThree(int[] nums,int left,int mid,int right){
        if((nums[left] < nums[mid])^(nums[left] < nums[right])){
            return left;
        }else if((nums[right] < nums[mid])^(nums[right] < nums[left])){
            return right;
        }else{
            return mid;
        }
    }
    public static int partition(int[] nums,int left,int right){
        int pivot = medianThree(nums,left,(left+right)/2,right);
        swap(nums,left,pivot);
        int i = left;
        int j = right;
        while(i < j){
            while(i < j && nums[j] >= nums[left]){
                j--;
            }
            while(i < j && nums[i] <= nums[left]){
                i++;
            }
            swap(nums,i,j);
        }
        swap(nums,left,i);
        return i;
    }
    public static void quicksort(int[] nums,int left,int right){
        if(left >= right){
            return ;
        }
        int pivot = partition(nums,left,right);
        quicksort(nums,left,pivot-1);
        quicksort(nums,pivot+1,right);
    }

 参考:11.5   快速排序 - Hello 算法 (hello-algo.com)

你可能感兴趣的:(排序算法,数据结构,算法)