【排序算法Java实现】快速排序

本文介绍了Java中快速排序算法的实现,包括平均、最优和最差时间复杂度,以及空间复杂度。特别指出,通过随机选择partition可以避免算法在数组有序情况下的退化,从而提高效率。实际测试显示,对于已排序的数组,优化后的快速排序算法执行时间从40-60ms降低到20-30ms。
摘要由CSDN通过智能技术生成

代码如下

    public void quickSort(int[] nums){
//        high从length-1开始,否则nums[high]超出范围
        quickSort(nums, 0, nums.length - 1);
    }

    public void quickSort(int[] nums, int low, int high){
        if (low >= high)
            return;
//        记录左右初始指针
        int left = low;
        int right = high;
//        记录锚点,选择数组第一位
        int pivot = nums[left];
//        保证左右指针相遇即停止
        while (left < right){
//            由于这里要不断移动指针,也要进行判断
            while (left < right){
//                先从数组右侧查找,按照快排思想,比锚点大的都应该在锚点右侧,因此判断右侧开始大于等于锚点的直接跳过
                if (nums[right] >= pivot){
                    right--;
                }else {
//                    如果比锚点小,说明应该在锚点左侧,直接把当前right值赋给left处,
//                    由于首次开始时left上的值已经保存在pivot中,不用担心覆盖导致丢失
                    nums[left] = nums[right];
                    break;
                }
            }

            while (left < right){
//                右侧经过一次变换后,开始从左侧找有没有比锚点大的值,有就赋给right所在的位置
                if (nums[left] <= pivot){
                    left++;
                }else {
                    nums[right] = nums[left];
                    break;
                }
            }
        }
//        左右指针相遇的时候跳出循环,此时left和right重合的位置就应该是锚点pivot所在的位置
        int pivotIndex = left;
        nums[left] = pivot;

//        把数组依据锚点分成左右两个子数组,进入quickSort做递归,直到左右子数组元素为1或0跳出
//        左子数组
        quickSort(nums, low, pivotIndex - 1);
//        右子数组
        quickSort(nums, pivotIndex + 1, high);
    }

平均时间复杂度:O(NlgN)
最优时间复杂度:O(NlgN)
最差时间复杂度:O(N^2)
空间复杂度:O(lgN)
稳定性:不稳定

上面的算法可能在极端情况下(数组已经有序)退化成O(N^2)的算法

下面的方式随机在数组中选择一个数作为partition,不会让算法退化

/**
 * @Description:
 * 快速排序3.0
 * @Author: chong
 * @Data: 2021/6/20 3:49 下午
 */
public class QuickSortTemplate_3 {
    public void quickSort(int[] nums){
        quickSort(nums, 0, nums.length - 1);
    }

    public void quickSort(int[] nums, int low, int high){
        if (low >= high)
            return;
//        随机在nums数组中选择一个数,让其和low做交换,保证选到合适的partition
        swap(nums, low + (int) (Math.random() * (high - low + 1)), low);
        int partition = partition(nums, low, high);
        quickSort(nums, low, partition);
        quickSort(nums, partition + 1, high);
    }

    public int partition(int[] nums, int low, int high){
        int left = low;
        int right = high;
        int pivot = nums[left];
        while (left < right){
            while (left < right){
                if (nums[right] >= pivot)
                    right--;
                else {
                    nums[left] = nums[right];
                    break;
                }
            }
            while (left < right){
                if (nums[left] <= pivot)
                    left++;
                else {
                    nums[right] = nums[left];
                    break;
                }
            }
        }
        nums[left] = pivot;
        return left;
    }

    private void swap(int[] nums, int a, int b){
        int temp = nums[a];
        nums[a] = nums[b];
        nums[b] = temp;
    }


    @Test
    public void test(){
//        int[] nums = {5, 9, 1, -4, 5, 3, 7, 6, 1, 32, 23, 42, 57, 2, -49, 4, 67};
//        这个例子能很好的展示3.0和之前的快排在时间上的差距
        int[] nums = new int[10000];
        for (int i = 0; i < 10000; i++){
            nums[i] = i;
        }
        quickSort(nums);
        System.out.println(Arrays.toString(nums));
    }
}

其中已经排好序的0-9999的数组采用快速排序算法,之前的算法时间在40-60ms左右,改进后在20-30ms左右。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值