小顶堆与topK的具体代码实现:
求海量数据(正整数)按逆序排列的前k个数(TopK),因为数量太大,不能全部存储在内存中,只能一个一个地从磁盘或者网络上读取数据,请设计一个高效的算法来解决这个问题。
第一行:用户输入K,代表要求得topK。
随后的N(不限制)行,每一行是一个整数,代表用户输入的数据。
用户输入-1代表输入终止。
请输出topK,从小到大,空格分割。
解决:大顶堆。
思路:
输入N个数据时,若n<k,依次添加到数组(堆)当中;当填入数据达到k时,立刻堆化。
若n>k,比较要填入数与堆顶数据,若x>heap[0],将heap[0]赋值为x,并向下堆化。
ps:n:已填入数据的数量。
代码:
#include<iostream>
using namespace std;
int* heap; //全局变量 ===> 数组头指针(数组名)
int size=0;
int k; //输出前k个数
/*******/
void deal(int x);
void makeMinHeap(int A[],int length);
void MinHeapFixDown(int A[],int i,int n);
void printRs();
/*******/
int main(){
std::ios_base::sync_with_stdio(false);
cin>>k;
heap=new int[k]; // 动态创建数组
int x;
while((cin>>x)&&x!=-1){
deal(x); //处理x
}
printRs();
return 0;
}
/*
如果数据的数量小等于k,直接加入堆中
等于k的时候,进行堆化
*/
void deal(int x){
if(size<k){
heap[size++]=x;
if(size==k){
//堆化
makeMinHeap(heap,k);
}
}
else{
//x和堆顶进行比较,如果x大于堆顶,x将堆顶挤掉,并向下调整
if(heap[0]<x){
heap[0]=x;
MinHeapFixDown(heap,0,k);
printRs();
}
}
}
void printRs(){
for(int i=0;i<k;i++){
cout<<heap[i]<<" ";
}
cout<<endl;
}
void makeMinHeap(int A[],int length){
int n=length;
for(int i=n/2-1;i>=0;i--){
MinHeapFixDown(A,i,n);
}
}
//向下调整函数
void MinHeapFixDown(int A[],int i,int n){
//找到左右孩子
int left=2*i+1;
int right=2*i+2;
//左孩子已经越界,i就是叶子节点
if(left>=n){
return;
}
int min=left;
if(right>=n){
min=left;
}
else{
if(A[right]<A[left]){
min=right;
}
}
//min指向了左右孩子中较小的那个
//如果A[i]比两个孩子都要小,不用调整
if(A[i]<A[min]){
return;
}
//否则,找到两个孩子中较小的,和i交换
int temp=A[i];
A[i]=A[min];
A[min]=temp;
//小孩子那个位置的值发生了变化,i变更为小孩子的那个位置,递归调整
MinHeapFixDown(A,min,n);
}