快速排序

基本思想

取待排序序列中任意一个元素作为分区点(一般取第一个元素或最后一个元素)。
按分区点将小于分区点的元素放在左边,将大于分区点的元素放在右边。

核心:分治。使用递归的方法,对分开的两块区域一直进行快速排序。直到区间缩小为1,就说明所有数据都有序了

取得分区点实现

数组array[low...high]:
将待排序数组的第一个元素array[low]作为分区点。
array[low+1...j]存放的是小于分区点的值,array[j+1...high]存放的是大于分区点的值。
然后,交换array[j]和分区点的值。
这样就能保证所有小于分区点的元素,都在分区点左侧;所有大于分区点的元素,都在分区点右侧。
最后,返回分区点下标。

实现代码

/**
 * @Author: snayi
 * @CreateTime: 2019-08-05 15:11
 * @Description:
 */
public class QuickSort {
    public static void quickInternal(int[] array) {
        int n = array.length;
        if (n <=1) {
            return;
        }
        quickInternal(array,0,n-1);
    }

    /**
     *  快排的递归实现
     * @param array
     * @param low 数组第一个元素下标
     * @param high 数组最后一个元素下标
     */
    public static void quickInternal(int[] array,int low,int high) {
        //递归出口
        if (low >= high) {
            return;
        }
        //获取分区点

        int pivot = partition(array,low,high);
        //分区快排
        quickInternal(array,low,pivot-1);
        quickInternal(array,pivot+1,high);
    }

    /**
     * 获得数组分区点
     * @param array 带排序数组
     * @param low   数组开始点下标
     * @param high  数组结束点下标
     * @return  数组分区点
     */
    public static int partition(int[] array,int low,int high) {
        //默认数组分区点为当前数组第一个元素,将其值保存下来
        int pivot = array[low];
        //小于分区点的最后一个值下标
        int j = low;
        //使用下标i遍历整个数组的值
        for (int i = low+1; i <= high ; i++) {
            //当前值小于分区点值
            if (array[i] < pivot) {
                //将当前值和j+1位置的值交换。让小于分区点的值增加一个
                swap(array,j+1,i);
                //小于分区点的值多了一个,j后移
                j++;
            }
        }
        //交换分区点的值,使其处在中间位置
        swap(array,low,j);
        //返回分区点下标
        return j;
    }
    /**
    *交换元素
    */
    public static void swap(int[] array,int x,int y) {
        int temp = array[x];
        array[x] = array[y];
        array[y] = temp;
    }
    public static void main(String[] args) {
        int[] array = new int[]{8,10,2,3,6,1,5};
        System.out.println("快排前的数组");
        SortHelper.printArray(array);
        System.out.println("快排后的数组");
        quickInternal(array);
        SortHelper.printArray(array);

    }
}

指标分析

  • 时间复杂度
    最好时间复杂度:分区均衡,O(nlogn)
    最坏时间复杂度:分区极其不均衡(已经是有序数组,选择其中最大的数来分),O(nlogn)
    平均时间复杂度:O(nlogn)
  • 空间复杂度: O(1)。原地排序,没有产生额外空间。
  • 稳定性:不稳定

快排优化

二路快排

原始快排分区时没有考虑与分区点值相等的元素。
若等于分区值的重复元素太多,会导致分区不平衡,时间复杂度退化为O(n^2)。

实现思路

将小于分区点值(array[pivotIndex])和大于分区点值的元素放在数组的两端
双指针实现:
	1.在当前数组中随机选取一个值作为分区点,然后将其与数组第一个元素array[low]交换
	2.两个指针i、j,i从low+1开始向后遍历,j从high开始向前遍历
	array[low+1...i-1]存放小于分区点的值,array[j+1...high]存放小于分区点的值
	3.如果array[i]小于array[pivotIndex],则i向后走;否则i停下,等待与j交换值。
	如果array[j]大于array[pivotIndex],则j向前走;否则j停下,等待与i交换值。
	循环执行以上步骤。
	4.如果i>j,则跳出循环。然后将j的值与low的值交换,返回分区点下标j。
  • 当前数组
    在这里插入图片描述
  • i碰到了一个大于povit的值。j碰到了一个小于povit的值
    在这里插入图片描述
  • i和j对应的数据交换之后再继续循环
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值