美文网首页
ologn排序算法后的两个问题

ologn排序算法后的两个问题

作者: 邵俊颖 | 来源:发表于2018-08-29 21:54 被阅读0次

    求一个数组的逆序数对的个数(归并排序)

        // merge函数求出在arr[l...mid]和arr[mid+1...r]有序的基础上, arr[l...r]的逆序数对个数
        private static long merge(Comparable[] arr, int l, int mid, int r) {
    
            Comparable[] aux = Arrays.copyOfRange(arr, l, r+1);
    
            // 初始化逆序数对个数 res = 0
            long res = 0L;
            // 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1
            int i = l, j = mid+1;
            for( int k = l ; k <= r; k ++ ){
    
                if( i > mid ){  // 如果左半部分元素已经全部处理完毕
                    arr[k] = aux[j-l];
                    j ++;
                }
                else if( j > r ){   // 如果右半部分元素已经全部处理完毕
                    arr[k] = aux[i-l];
                    i ++;
                }
                else if( aux[i-l].compareTo(aux[j-l]) <= 0 ){  // 左半部分所指元素 <= 右半部分所指元素
                    arr[k] = aux[i-l];
                    i ++;
                }
                else{   // 右半部分所指元素 < 左半部分所指元素
                    arr[k] = aux[j-l];
                    j ++;
                    // 此时, 因为右半部分k所指的元素小
                    // 这个元素和左半部分的所有未处理的元素都构成了逆序数对
                    // 左半部分此时未处理的元素个数为 mid - j + 1
                    res += (long)(mid - i + 1);
                }
            }
    
            return res;
        }
    
        // 求arr[l..r]范围的逆序数对个数
        // 思考: 归并排序的优化可否用于求逆序数对的算法? :)
        private static long solve(Comparable[] arr, int l, int r) {
    
            if (l >= r)
                return 0L;
    
            int mid = l + (r-l)/2;
            // 求出 arr[l...mid] 范围的逆序数
            long res1 = solve(arr, l, mid);
            // 求出 arr[mid+1...r] 范围的逆序数
            long res2 = solve(arr, mid + 1, r);
    
            return res1 + res2 + merge(arr, l, mid, r);
        }
    
        public static long solve(Comparable[] arr){
    
            int n = arr.length;
            return solve(arr, 0, n-1);
        }
    

    求出nums里第k小的数(快速排序)

        // 对arr[l...r]部分进行partition操作
        // 返回p, 使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p]
        // partition 过程, 和快排的partition一样
        // 思考: 双路快排和三路快排的思想能不能用在selection算法中? :)
        private static int partition(Comparable[] arr, int l, int r){
    
            // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot
            swap( arr, l , (int)(Math.random()*(r-l+1))+l );
    
            Comparable v = arr[l];
    
            int j = l; // arr[l+1...j] < v ; arr[j+1...i) > v
            for( int i = l + 1 ; i <= r ; i ++ )
                if( arr[i].compareTo(v) < 0 ){
                    j ++;
                    swap(arr, j, i);
                }
    
            swap(arr, l, j);
    
            return j;
        }
    
        // 求出nums[l...r]范围里第k小的数
        private static Comparable solve(Comparable[] nums, int l, int r, int k){
    
            if( l == r )
                return nums[l];
    
            // partition之后, nums[p]的正确位置就在索引p上
            int p = partition(nums, l, r);
    
            if( k == p )    // 如果 k == p, 直接返回nums[p]
                return nums[p];
            else if( k < p )    // 如果 k < p, 只需要在nums[l...p-1]中找第k小元素即可
                return solve( nums, l, p-1, k);
            else // 如果 k > p, 则需要在nums[p+1...r]中找第k-p-1小元素
                 // 注意: 由于我们传入__selection的依然是nums, 而不是nums[p+1...r],
                 //       所以传入的最后一个参数依然是k, 而不是k-p-1
                return solve( nums, p+1, r, k );
        }
    
        // 寻找nums数组中第k小的元素
        // 注意: 在我们的算法中, k是从0开始索引的, 即最小的元素是第0小元素, 以此类推
        // 如果希望我们的算法中k的语意是从1开始的, 只需要在整个逻辑开始进行k--即可, 可以参考solve2
        public static Comparable solve(Comparable nums[], int k) {
    
            assert nums != null && k >= 0 && k < nums.length;
            return solve(nums, 0, nums.length - 1, k);
        }
    
        // 寻找nums数组中第k小的元素, k从1开始索引, 即最小元素是第1小元素, 以此类推
        public static Comparable solve2(Comparable nums[], int k) {
    
            return Selection.solve(nums, k - 1);
        }
    
        private static void swap(Object[] arr, int i, int j) {
            Object t = arr[i];
            arr[i] = arr[j];
            arr[j] = t;
        }
    

    相关文章

      网友评论

          本文标题:ologn排序算法后的两个问题

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