堆排序的使用

213 阅读1分钟

1. 数据流中第K大的数据

解法一:记录前K个的最大值:每次进来一个比K个值里面最小值大的数,踢出K个值里面最小的那个数,把最新的那个数记录进K个值里面(先排序,使用快排),快排的时间复杂度是KlogK,有k个值,所以该解法的复杂度为O(N*K(logK))

解法二:使用优先队列(priorityQueue)维持一个小顶堆(min heap)

img

java中的优先队列,priorityQueue的作用是保证每次取出的元素都是队列中权值最小的。其通过堆实现,具体说是通过完全二叉树(complete binary tree)实现的小顶堆(任意一个非叶子节点的权值,都不大于其左右子节点的权值)

public class HeapData {
    private  PriorityQueue<Integer> pq = null;
    private int k;

    public  int add(int val) {
        if(pq.size() < k)//如果队列中的数量少于K,直接添加入优先队列,优先队列会自动维持小顶堆
            pq.offer(val);
        else{
            if(pq.peek() < val){//否则队列中的数量大于或者等于K,优先队列中的最小数字小于新的数据,优先队列中的顶堆要被移除,并且添加入新的数据进优先队列
                pq.poll();
                pq.offer(val);
            }

        }
        return pq.peek();//返回当前第K大的数
    }

    public  HeapData(int k, int[] nums) {
        this.k = k;
        pq = new PriorityQueue<>(k);

        for(int i : nums){//对传进来的int数组遍历
            add(i);
        }
    }
}

维持小顶堆的时间复杂度是Log2K,遍历的有N个数据,所以时间复杂度为O(Nlog2K)

2. 最小的K个数

输入n个整数,找出其中最小的K个数。例如 输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

思路1:

  • 1、使用最大堆,构建容量为K的最大堆

  • 2、遍历数组,每次比较数组中的元素与堆顶元素大小,堆堆顶小入堆即可

    public static ArrayList<Integer> getLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> ret = new ArrayList<>();
        if (input == null || k == 0) {
            return ret;
        }
    
        int len = input.length;
        if (len < k) {
            return ret;
        }
    
        // 构建大顶堆
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(k, new Comparator<Integer>(){
    
            @Override
            public int compare(Integer o1, Integer o2)
            {
                return o2 - o1;
            }
        });
    
        // 遍历数组,把比堆顶元素小的元素加入最大堆中
        for (int i=0; i<len; i++) {
            int curVal = input[i];
            System.out.println(maxHeap.size()+",curlval:"+curVal);
            if (maxHeap.size() < k) {
                maxHeap.add(curVal);
            } else {
                // 堆顶元素大于当前元素,则弹出堆顶元素,加入当前元素到堆中
                if (maxHeap.peek() > curVal) {
                    maxHeap.poll();
                    maxHeap.add(curVal);
                }
            }
        }
    
        // 最大堆所有元素加入要返回的list中
        ret.addAll(maxHeap);
    
        return ret;
    }