排序算法 - 快速排序 Java实现

什么是快排?

快排是对冒泡排序的一种改进,通过多次比较和交换来实现排序,排序的流程如下
(1)首先设定一个分界值,通过该分界值将数组分成左右两部分。
(2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于分界值,而右边部分中各元素都大于或等于分界值。
(3)然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
(4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了

快排的时间复杂度

想要更好的计算时间复杂度,我们必须了解快排的思想,首先 快排第一次需要完全遍历一次数组,来将比分界值小的移动到分界值的左边,比分界值大的,移动到分界值的右边,然后分别再对分界值两边的数组进行同样的操作
理想的情况是,每次划分所选择的中间数恰好将当前序列几乎等分,经过log2n趟划分,便可得到长度为1的子表。这样,整个算法的时间复杂度为O(nlog2n)
最坏的情况是,每次所选的中间数是当前序列中的最大或最小元素,这使得每次划分所得的子表中一个为空表,另一子表的长度为原表的长度-1。这样,长度为n的数据表的快速排序需要经过n趟划分,使得整个排序算法的时间复杂度为O(n2)
为了改善快速排序最差的情况,我们引入了三数取中随机数两种选择分界值的的方法,本文只演示其中随机数的方法
所需要栈的最大深度为O(log2n), 所以空间复杂度为O(log2n)

public class QuickSort {
    public static void main(String[] args) {
        int[] ints1 = {1,4,5,2,3,6,9,8,7};
        quickSort(ints1);
        for (int re : ints1) {
            System.out.print(re +  "-");
        }
    }
    public static int[] quickSort(int[] nums){
        quick(nums,0,nums.length-1);
        return nums;
    }
    public static void quick(int[] nums, int begin, int end){
        if(begin >= end){
            return;
        }
        //取得中间值
        int rPartition = randomPartition(nums,begin, end);
        // 将中间值放到数组的第一个位置
        swap(nums,begin,rPartition);
        int partition = partition(nums,begin,end) ;
        quick(nums,begin,partition-1);
        quick(nums,partition+1,end);
    }
    // 根据随机数进行取中间值
    public static int randomPartition(int start, int end){
        Random r =  new Random();
        int val = r.nextInt(start,end);
        return val;
    }
		
    public static int partition(int[] nums, int begin, int end){
    //把左边挖空 作为基准值
        int tmp = nums[begin];
        while(begin < end){
       //挖空法,将最左侧挖空,然后持续交换左右的数,知道左右指针汇合
            while(begin < end && nums[end] >= tmp){
                end--;
            }
            // 当遇到右侧值小于左侧的时候,将右侧的值直接放到左侧的坑中,右侧变坑
            nums[begin] = nums[end];
            while(begin < end && nums[begin] <= tmp){
                begin++;
            }
            // 这个时候,右侧又变成坑了,当遇到左侧值大于右侧的时候,把左侧的值放到右侧,左侧变坑
            nums[end] = nums[begin];
        }
        // 当两指针相汇合的时候,说明这个地方 就应该是中间值的位置,把之前挖出来的值放进去
        nums[begin] = tmp;
        return begin;
    }

    /**
     * 用于交换数组两个位置的值
     * @param nums 需要被交换的数组
     * @param a
     * @param b
     */
    public static void swap(int[] nums, int a, int b){
        int tmp = nums[a];
        nums[a] = nums[b];
        nums[b] = tmp;
    }
}

一次排序的过程如下
请添加图片描述

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值