ITPub博客

首页 > IT职业 > IT图书 > 快速排序-优化

快速排序-优化

IT图书 作者:cityvag 时间:2021-09-09 09:25:28 0 删除 编辑

随机化优化

上面提到了最常规的排序,排序,然而在面对完全有序的数组时,快速排序的效率明显降低到了O(n^2)。快速排序划分的子数组越不平衡,快排就会降低。

快速排序采用的是分而治之的思想,如果数组完全有序的话,快排分层级提升到了n,而每次都要与所有的元素进行对比。因此在面对完全有序元素时,可对快速排序进行如下优化:

随机寻找下标,不直接从最左边开始寻找。

 private static int partition(int[] arr, int l, int r) {

        //原本默认从最左边开始
        //新增下面一行,这回每次partion一般不会从最左边开始,划分的次数也不会降低到n
        swap(arr,l, new Random().nextInt((r-l)) + l );

        int v = arr[l];
        int j = l;

        for (int i = l + 1; i 

双路快速排序

  1. 定义两个下标
    图片描述

  2. i 的位置向后扫描到(e = arr[i]) >= v,然后i停止
    图片描述

  3. 然后j往前扫描,直到arr[j] 图片描述

  4. 这个时候交换arr[i]和arr[j]的位置
    图片描述

图片描述

  1. i再往后移动下一个位置,j继续往前移动一个位置,直到i和j重合。

当出现大量重复元素的时候,重复的元素也会分配在橙色区域和紫色区域,这样划分的区域就不会特别偏向某一方。

实现:

   public static void sort(int[] arr){
        sort(arr,0,arr.length - 1);
    }

    private static void sort(int[] arr, int l, int r) {
        if (l >= r){
            return;
        }

        int p = partition2(arr,l,r);
        sort(arr,l,p);
        sort(arr,p + 1,r);

    }

    private static int partition2(int[] arr, int l, int r) {
        Hepler.swap (arr,l,new Random().nextInt((r-l)) + l);
        int i = l + 1;
        int j = r;
        int v = arr[l];
        log.info("当前比较的v = {}",v);
        while (true){
            while (i = l && arr[j] > v){
                j--;
            }

            if (i > j){
                break;
            }
            log.info("交换前数组:{}",arr);
            Hepler.swap(arr,i,j);
            log.info("找到的i = {},j={}",i,j);
            log.info("交换后数组:{}",arr);
            i++;
            j--;
        }

        Hepler.swap(arr,l,j);
        log.info("一次partion的数组:{}",arr);
        return j;

    }

三路快速排序

之前排序都是将元素分为小于v,大于v。而三路快速排序,则将元素划分为:

  • 大于v
  • 小于v
  • 等于v

流程:

  1. 定义3个会移动的索引,lt,i,gt, i指向当前要比较的元素
    图片描述

  2. 当arr[i] == v的时候,那么e直接纳入绿色的部分
  3. 当arr[i]

图片描述

  1. 当arr[i] > v的时候,只需要把arr[i]和arr[gt - 1]的元素交换位置,但是i的位置不用变,gt的元素向前移动一个元素。
    图片描述

  2. 整个元素处理完成之后
    图片描述

实现:


    public static void sort(int[] arr){
        quickSortThreeWays(arr,0,arr.length - 1);
    }

    private static void quickSortThreeWays(int[] arr, int l, int r){
        if (r  v
        //数组中最后一个元素
        int gt = r + 1;
        // arr[lt + 1...i] == v
        //第一个元素开始
        int i = l + 1;

        while (true){

            if (arr[i] == v){
                i++;
            }else if (arr[i]  v){
                Hepler.swap(arr,i,gt - 1);
                gt--;
            }
            log.info("当前i={} , lt = {},gt = {}",i,lt,gt);
            log.info("当前数组{}",arr);
            if (i >= gt){
                break;
            }
        }

        Hepler.swap(arr,l,lt );
        log.info("一次quickSort数组{}",arr);
        quickSortThreeWays(arr,l,lt - 1);
        quickSortThreeWays(arr,gt,r);

    }

最后

在《剑指Offer》上看到一句话,查找相对而言较为交单,不外乎顺序查找,二分查找,哈希查找和二叉树排序查找,在面试的时候不管使用循环还是递归,面试官都期待应聘者能信手沾来的写出完整的二分查找代码,否则连继续面试的兴趣都没有。

排序是算法中的基础,加油。

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/3518/viewspace-2809796/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2019-08-30

  • 博文量
    79
  • 访问量
    742