【算法】手撕快排

快排

  • 基本思想:
    • 分治法+递归。
    • 快排主要分两个部分:
      • partition:选一个pivot,将数组分成左右两个部分。
        • 左边的数据都小于 pivot,右边的都大于 pivot。
      • recursive:
        • 快排pivot 的 左边部分 与 右边部分。
  • 填坑法:

在这里插入图片描述

  • 代码:

    class Solution {
        public int[] sortArray(int[] nums) {
            quickSort(nums, 0, nums.length-1);
            return nums;
        }
    
        private void quickSort(int[] nums, int l, int r){
            if(l>=r) return;
            int pos = partition(nums, l, r);
            quickSort(nums, l, pos-1);
            quickSort(nums, pos+1, r);
        }
    
        private int partition(int nums[], int l, int r){
            int pivot = nums[l];
            while(l<r){
                while(r>l && nums[r]>=pivot) r--;
                nums[l] = nums[r];
                // System.out.println(Arrays.toString(nums)+", l: "+l+", r: "+r);
                while(l<r && nums[l]<=pivot) l++;
                nums[r] = nums[l];
                // System.out.println(Arrays.toString(nums)+", l: "+l+", r: "+r);
            }
            nums[l] = pivot;
            // System.out.println(Arrays.toString(nums)+", l: "+l+", r: "+r);
            return l;
        }
    }
    
  • 优化pivot的选择:随机选择pivot,然后把pivot swap到 左边left的位置,其余都可以按照上面写。

    class Solution {
        public int[] sortArray(int[] nums) {
            quickSort(nums, 0, nums.length-1);
            return nums;
        }
    
        private void quickSort(int[] nums, int l, int r){
            if(l>=r) return;
            int pos = partition(nums, l, r);
            quickSort(nums, l, pos-1);
            quickSort(nums, pos+1, r);
        }
    
        private int partition(int[] nums, int l, int r){
            int pivot = getPivot(nums, l, r);
            while(l<r){
                while(r>l && nums[r]>=pivot) r--;
                nums[l] = nums[r];
                while(l<r && nums[l]<=pivot) l++;
                nums[r] = nums[l];
            }
            nums[l] = pivot;
            return l;
        }
    
        private int getPivot(int[] nums, int l, int r){
            int i = new Random().nextInt(r-l+1)+l;
            swap(nums, l, i);
            return nums[l];
        }
    
        private void swap(int[] nums, int a, int b){
            int t = nums[a];
            nums[a] = nums[b];
            nums[b] = t;
        }
    }
    

快排的复杂度

  • 空间复杂度:使用了递归,每次递归用常数级的空间,因此: O(logn)
  • 时间复杂度:
    • 最好的情况:每次partition 后 pivot 都在中间,递归 O(logn) 次,每次 partition 需要 O(n),最好情况下的时间复杂度为 O(nlogn)
    • 最差的情况:数组是已经是有序的,pivot partition后的位置总是在边上,T(n) = T(n-1) + T(0) + O(n),需要递归 O(n) 次,复杂度为 O(n^2)
    • 平均情况: O(nlogn)

参考

  • 20
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值