美文网首页
排序算法的一些优化和改进2

排序算法的一些优化和改进2

作者: 滨岩 | 来源:发表于2020-02-23 18:09 被阅读0次

    6、快速排序 O(nlogn)

       public static void sort(Comparable[] arr) {
            quickSort(arr, 0, arr.length - 1);
        }
    
        
        //递归使用快速排序,对arr[left...right]的范围进行排序
        private static void quickSort(Comparable[] arr, int left, int right) {
    
            if (left >= right) {
                return;
            }
    
            int partitionIndex = partition(arr, left, right);
            quickSort(arr, left, partitionIndex - 1);
            quickSort(arr, partitionIndex + 1, right);
    
        }
        
        // 对arr[left...right]部分进行partition操作
        //返回partitionIndex 是的arr[left...partition-1]<arr[partitionIndex];  arr[partion+1...r]>arr[partitionIndex]
        private static int partition(Comparable[] arr, int left, int right) {
    
            Comparable v = arr[left];
    
            int partitionIndex = left;
            for (int i = left + 1; i <= right; i++) {
                if (arr[i].compareTo(v) < 0) {
                    SortTestHelper.swap(arr, partitionIndex, i);
                    partitionIndex++;
                }
            }
    
            arr[partitionIndex] = v;
    
            return partitionIndex;
        }
    

    递归使用快速排序,对arr[left...right]的范围进行排序
    对arr[left...right]部分进行partition操作
    返回partitionIndex 是的arr[left...partition-1]<arr[partitionIndex]; arr[partion+1...r]>arr[partitionIndex]

    快速排序也可以进行优化,当元素个数小于15的时候,比较接近有序状态,可以用针对有序队列排序效率高的插入排序进行优化,代码如下:

        //递归使用快速排序,对arr[left...right]的范围进行排序
        private static void quickSort(Comparable[] arr, int left, int right) {
    
            if (left >= right) {
                return;
            }
    
           if(right-left<=15){
              insertSort(arr,left,right);
           }
    
            int partitionIndex = partition(arr, left, right);
            quickSort(arr, left, partitionIndex - 1);
            quickSort(arr, partitionIndex + 1, right);
    
        }
    
        //插入排序 
        public static void insertSort(Comparable[] arr,int left,int right) {
            for (int i = left; i <=right; i++) {
                for (int j = i; j > left; j--) {
                    if (arr[j].compareTo(arr[j - 1]) > 0) {
                        break;
                    }
    
                    SortTestHelper.swap(arr, j, j - 1);
                }
            }
        }
    

    快速排序性能会比归并排序效率要高,但是有人对于接近有序队列,快速排序要比归并排序性能要差很多,归并排序每次平分的平衡性要比快速排序的要好,归并排序拆分的高度能保证是logn的,而快速排序并不能保证高度为logn,所以快速排序最坏的情况是退化为O(n^2)的。

    快速排序不需要额外的空间。如果数据量大而且数据全部存放在内存中,那么

    快速排序是首选的排序方法。具体的排序过程是先将元素分成两个区,所有小于某个元素的值在第一个区,其他元素在第二区。然后分别对这两个区进行快速排序,直到所分的区只剩下一个元素为止。

    为了解决快速排序分割数组时,分布不均的问题,每次选择partitionIndex的时候,采用随机生成的方式 ,详见下面代码的:
    SortTestHelper.swap(arr, left, (int) (Math.random() * (right - left + 1)) + left);
    或者
    Integer randomIndex = left+random.nextInt(right - left + 1);
    SortTestHelper.swap(arr, left, randomIndex);

        // 对arr[left...right]部分进行partition操作
        //返回partitionIndex 是的arr[left...partition-1]<arr[partitionIndex];  arr[partion+1...r]>arr[partitionIndex]
        private static int partition(Comparable[] arr, int left, int right) {
    
            //Comparable v = arr[left];
            // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot
            SortTestHelper.swap(arr, left, (int) (Math.random() * (right - left + 1)) + left);
            Comparable v = arr[left];
            int partitionIndex = 0;
            for (int i = left + 1; i <= right; i++) {
                if (arr[i].compareTo(v) < 0) {
                    SortTestHelper.swap(arr, partitionIndex, i);
                    partitionIndex++;
                }
            }
    
            arr[partitionIndex] = v;
    
            return partitionIndex;
        }
    

    当需要排序的数据含有大量的重复元素的时候,快速排序的子序列的划分会极其不平衡,二分递归会退化为线性递归,递归深度接近于O(n)。为了解决这个问题,可以采用双排或者三排

    快速排序 双排

    private static int partition(Comparable[] arr, int left, int right) {
            //随机选一个 povit
            int swapLeft = (int) (Math.random() * (right - left + 1) + left);
            SortTestHelper.swap(arr, left, swapLeft);
    
            Comparable v = arr[left];
            int i = left + 1;
            int j = right;
            while (true) {
                while (i <= right && arr[i].compareTo(v) < 0) {
                    i++;
                }
                while (j >= left+1 && arr[j].compareTo(v) > 0) {
                    j--;
                }
    
                if (i >j) {
                    break;
                }
    
                SortTestHelper.swap(arr, i, j);
                i++;
                j--;
            }
            SortTestHelper.swap(arr, left, j);
            return j;
        }
    

    快速排序 三路快排思想

    // 递归使用快速排序,对arr[l...r]的范围进行排序
        private static void quickSortThreeWays(Comparable[] arr, int left, int right) {
    
            if (left >= right) {
                return;
            }
    
            // 对于小规模数组, 使用插入排序
            if (right - left <= 15) {
                //优化代码
            }
    
            // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot
            int swapLeft = (int) (Math.random() * (right - left + 1) + left);
            SortTestHelper.swap(arr, left, swapLeft);
            Comparable v = arr[left];
    
            int lt = left;  // arr[l+1...lt] < v
            int gt = right + 1; //  arr[gt...r] > v
            int et = left + 1;// arr[lt+1...i) == v
    
            while (et < gt) {
    
                if (arr[et].compareTo(v) < 0) {
                    if (et != lt + 1) {
                        SortTestHelper.swap(arr, et, lt + 1);
                    }
                    et++;
                    lt++;
                    continue;
                }
    
                if (arr[et].compareTo(v) > 0) {
                    SortTestHelper.swap(arr, et, gt - 1);
                    gt--;
                    continue;
                }
                //arr[et].compareTo(v) == 0
                et++;
            }
    
            SortTestHelper.swap(arr, left, lt);
            //et 的 不变
            quickSortThreeWays(arr, left, lt - 1);
            quickSortThreeWays(arr, gt, right);
        }
    

    相关文章

      网友评论

          本文标题:排序算法的一些优化和改进2

          本文链接:https://www.haomeiwen.com/subject/xhcsqhtx.html