题目描述
- 求求海量数据(正整数)按逆序排列的前k个数(topK),因为数据量太大,不能全部存储在内存中,只能一个一个地从磁盘或者网络上读取数据,请设计一个高效的算法来解决这个问题。 第一行用户输入K,代表要求得topK 随后的N(不限制)行,每一行是一个整数代表用户输入的数据 直到用户输入-1代表输入终止 请输出topK,空格分割。
解题思路
- 最终需要逆序排列的前K个数,则一直维持一个大小为K的数组,当用户输入到数组被填满后(达到k个),对数组进行堆化(小顶堆),从此对每一个输入的数据与对顶元素进行比较,若比堆顶元素大(属于TopK)则替换掉堆顶元素,并进行小顶堆调整,直到输入结束,输出TopK。
代码
static int index=0;
static int[] heap;
static int k;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
k=sc.nextInt();
heap=new int[k];
int x=sc.nextInt();
while(x!=-1){
deal(x);
x=sc.nextInt();
}
System.out.println(Arrays.toString(heap));
}
private static void deal(int x) {
if(index<k){
heap[index++]=x;
if(index==k){
buildMinHeap(heap,heap.length);
}
}else {
if(heap[0]<x){
heap[0]=x;
minHeadAdjust(heap,0,heap.length);
System.out.println(Arrays.toString(heap));
}
}
}
private static void buildMinHeap(int[] heap, int length) {
for (int i = length/2-1; i >0 ; i--) {
minHeadAdjust(heap,i,heap.length);
}
}
private static void minHeadAdjust(int[] heap, int i, int length) {
int left=i*2+1;
int right=i*2+2;
if(left>=length){
return;
}
int min=left;
if(right<length&&heap[right]<heap[left]){
min=right;
}
if(heap[i]<=heap[min]){
return;
}else {
int temp=heap[i];
heap[i]=heap[min];
heap[min]=temp;
}
minHeadAdjust(heap,min,heap.length);
}