从一个数组中,找出前k个最大的元素,这就是经典的TopK问题。
接下来根据我自己的理解来解释最常用的一种TopK的解法。
需要建立一个大小为k的小堆
如果堆顶元素比当前遍历到的元素小,就需要让堆顶元素出堆,继续调整为小根堆,把这个元素放入堆中,数组遍历完之后,此时堆内的所有元素就是前k个最大的元素,堆顶元素就是第k大的元素。
import java.util.PriorityQueue;
public class TopK {
public static void main(String[] args) {
int [] array = {30,123,55,78,44,356};
topk(array,3);
}
public static void topk(int[] array,int k) {
PriorityQueue<Integer> minHeap = new PriorityQueue<>(k); //新建一个堆,默认是小根堆
for (int i = 0; i < array.length; i++) { //遍历数组
if(minHeap.size() < k) {
minHeap.offer(array[i]); //如果数组的长度小于k则直接把数组元素加入堆中
}else {
int top = minHeap.peek(); //peek()为队首元素 top=队首元素
if(top < array[i]) { // 堆顶元素与数组的元素比较,如果小于堆顶元素
minHeap.poll(); //则弹出堆顶元素,加入数组的元素。
minHeap.offer(array[i]); //堆会自己调整成小根堆
}
}
}
for (int i = 0; i < k; i++) {
System.out.print(minHeap.poll()+" ");
}
}
}
为什么poll会自动调整为小根堆?以下为poll()的函数
public int poll() {
if(isEmpty()) {
return -1;
}
int tmp = elem[0];
elem[0] = elem[this.usedSize-1];
elem[this.usedSize-1] = tmp;
this.usedSize--;
shiftDown(0,this.usedSize); //在堆中插入元素会自动调整
return tmp;
}