【Java】基础排序算法-快速排序

本文介绍了Java快速排序算法,包括基本原理、时间复杂度和空间复杂度。讨论了基本快排、随机快排和三路快排的优化思路,以及各自的代码实现和测试结果。通过优化,快速排序在处理不同类型的输入数据时表现出更好的性能。
摘要由CSDN通过智能技术生成

【Java】基础排序算法-快速排序



前言

快速排序是一种采用分治思想的排序算法,经过不同的优化手段之后可以适应于各种不同的输入数据,在一般应用中比其他排序算法都要快的多,因此快速排序是应用比较广泛的排序算法。


一、基本快排

在这里插入图片描述

基本快排原理

  1. 从待排序区间选择一个数,作为基准值(pivot);
  2. 切分(Partition): 遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基准值大的(可以包含相等的)放到基准值的右边;
  3. 采用分治思想,对基准值左右两个小区间按照同样的方式处理,直到小区间的长度为小于等于1,代表数组已经有序;

基准值的选择:

在处理不同的数据时基准值的选择可能是影响排序效率的关键

  1. 选择边上(左或者右):此方法有一个致命的缺点:对于近乎有序数组,每次选择边上元素作为基准值,会造成切分严重不平衡:
    例如举一个极端的例子:[1,2,3,4,5,6,7,9,8]数据量可以类比放大,此时如果我们选择左边第一个元素为基准值,每次处理只会移除一个元素,会导致整个排序过程会切分很多次,此时效率会非常差;对于这个问题我们可以有两种解决思路:
    a. 在处理此类数据之前,我们可以先将当前数组的顺序进行打乱,然后再排序,这样可以提升一定的效率,但是处理极端的数据时效果肯定不是最好的,且代码实现变得更加复杂;
    b.采用下面的另外两种选择方式;
  2. 随机选择:每次在待排序区间里随机选择一个索引作为基准值,可以有效的避免方法1带来的问题,而且代码实现有比较简单;
  3. 几数取中(例如三数取中):array[left], array[mid], array[right] 大小是中间的为基准值;

切分的过程:

假如我们要切分的数组区间为[i,j]

  1. 当我们确定基准值后,将基准值与待切分数组的第一个元素值进行交换(基准值选择边上,忽略次步骤);
  2. 记录基准值索引为 i(数组第一个元素索引) ,再确定两个指针索引 left=i, 从左向右遍历数组;right=j ,从右向左遍历数组;
  3. 再保证(left < right)的前提下:right指针先开始移动,当right所指元素小于基准值时,right暂停移动;left指针移动,当left所指元素大于基准值时,left暂停移动;
  4. 交换left与right所指元素值,然后left向右移动一位,right向左移动一位,重复步骤3,4;
  5. 经过步骤4后,left 所指向元素一定是最后一个小于基准值的元素,将left所指元素与 i 位置的基准值进行交换,最后返回left,则left位置就是第一次切分后的基准值的最终位置;

分治过程:

经过一次切分之后,对基准值左右两个小区间按照同样的方式处理,直到小区间的长度为小于等于1,代表整个数组已经有序

时间复杂度&空间复杂度

在这里插入图片描述

代码实现

    public static void quickSort(int[] arr) {
   
        //递归实现分治过程
        quickSortInternal(arr, 0, arr.length - 1);
    }
    //递归实现分治过程
    private static void quickSortInternal(int[] arr, int start, int end) {
   
        //递归出口 当数组元素小于等于1时
        if (start >= end) {
   
            return;
        }
        //记录切分点 切分点左侧数组元素值小于切分点值 右侧数组元素值大于切分点值
        int pivotIndex = partition(arr, start, end);
        //处理切分点左侧数组
        quickSortInternal(arr, start, pivotIndex - 1);
        //处理切分点右侧数组
        quickSortInternal(arr, pivotIndex + 1, end);
    }
    //切分实现过程
    private static int partition(int[] arr, int start, int end) {
   
        //我们直接默认数组第一个元素为基准值 实际这样并不合理 后面会进行优化
        int pivot = arr[start
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值