TopK问题(Java)

思路:

1、对于大数据量,采用分而治之的方法,构造HashMap分别组建 数据Hash值->数量的映射

2、分别对每一块应用topK数据排序

3、汇总每块的排序结果,再次进行topK排序

topK(k个最小的值)解法如下:

1、快排的思想,统计序号k前面的数据

2、构建元素为k个的最大堆,比堆顶元素小的入堆,弹出堆顶元素,重组最大堆。

代码:

package com.datastructure.array;


import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;

/**
 * top K问题
 * 取最小的k个数
 * 
 */
public class TopK
{
    
    /**
     * 取最小的k个数 
     */
    public static int[] getTopKByPartition(int[] arr, int k) {
        if (arr == null || arr.length <= 0 || k <= 1) {
            return null;
        }
        
        int size = arr.length;
        int target = k;
        
        int low = 0;
        int high = size - 1;
        
        int mid = getMid(arr, low, high);
        while (mid != target) {
            if (mid < target) {
                mid = getMid(arr, mid + 1, high);
            } else {
                mid = getMid(arr, low, mid - 1);
            }
        }
        int[] ret = new int[target];
        System.arraycopy(arr, 0, ret, 0, target);
        return ret;
    }

    /**
     * 快排思想-一趟排序
     */
    private static int getMid(int[] arr, int low, int high) {
        int base = arr[low];
        while (low < high) {
            // 判断条件必须加=场景,为<= 不能为<,否则数组中有相同数据时,会一直循环
            while (low < high && base <= arr[high]) {
                high--;
            }
            arr[low] = arr[high];
            
            // 判断条件必须加=场景,为>= 不能为>,否则数组中有相同数据时,会一直循环
            while (low < high && base >= arr[low]) {
                low++;
            }
            arr[high] = arr[low];
        }
        arr[low] = base;
        return low;
    }
    
    
    
    /**
     * 堆排序,组建一个(size+1)/2大小的最大堆 ,取到top (size+1)/2个小的值,则堆顶元素即为中位数
     * 
     * 先取前(size+1)/2个元素,组成最大堆,剩下的元素和堆顶比较,比堆顶大则忽略,比堆顶小则交换,然后重组最大堆
     */
    public static Queue<Integer> getTopKByMaxHeap(int[] arr, int k) {
        if (arr == null || arr.length <= 0 || k <= 1) {
            return null;
        }
        
        // 初步组建最大堆
        int heapSize = k;
        
        // JDK1.7 需指定初始大小,内部实现了最大堆(实现自定义从大到小排序)
        PriorityQueue<Integer> queue = new PriorityQueue<>(heapSize, new Comparator<Integer>() {

            @Override
            public int compare(Integer o1, Integer o2)
            {
                return o2 - o1;
            }
            
        });
        
        for (int i=0; i<heapSize; i++) {
            queue.offer(arr[i]);
        }

        // 比较余下元素,比堆顶小则替换堆顶元素为新值
        int size = arr.length;
        for (int j=heapSize;j<size;j++) {
            int temp = arr[j];
            // 当前元素比堆顶大 则删除堆顶元素,把当前元素加入堆
            if (queue.peek() > temp) {
                queue.poll();
                queue.offer(temp);
            }
        }
        
        // 返回堆顶元素
        return queue;
    }
    
    public static void main(String[] args)
    {
        int[] arr = {4,5,6,1,2,0,3,7,8,9,10,1,1,1,1,1,1};
        System.out.println(Arrays.toString(getTopKByPartition(arr, 10)));
        
        
        int[] arr2 = {4,5,6,1,2,0,3,7,8,9,10,1,1,1,1,1,1};
        System.out.println(getTopKByMaxHeap(arr2, 10));
    }

}

猜你喜欢

转载自blog.csdn.net/zangdaiyang1991/article/details/88652160
今日推荐