Top-K问题:一般是求数据集合中前k个最大或最小的元素,一般数据量很大。
比如专业排名的前十名,全国财富榜的前一百位富豪,一个游戏最强的前十名玩家等等。
对于Top-k问题,最容易想到的方法就是排序,但是当数据量过大时,数据很难同时加载到内存中,所以排序并不适合解决Top-k问题。最适合的方法是用堆进行解决。
基本思路:
1.用数据集合中的前K个元素建堆。(若是求最大的K个元素则建小堆;求最小的K个元素则建大堆)
2.用数据集合中剩余的N-K个元素依次与堆顶元素进行比较,若满足预设条件则替换掉堆顶元素,并对堆进行向下调整使之重新成为堆。将剩余的N-K个元素都比较完,堆中的K个元素就是最大/小的K个元素。
代码如下:
//交换函数
void Swap(int*p1,int*p2)
{
int tmp=*p1;
*p1=*p2;
*p2=tmp;
}
//向下调整函数
void AdjustDown(int*a,int n,int parent)
{
int child = parent*2+1;
while(child < n)
{
if(child+1<n && a[child+1]<a[child])
{
child++;
}
if(a[child]<a[parent])
{
Swap(&a[parent],&a[child]);
parent=child;
child=parent*2+1;
}
else
{
break;
}
}
}
int*getLeastNumbers(int*arr,int arrSize,int k,int*returnSize)
{
*returnSize=k;
if(k==0)
{
return NULL;
}
//开辟可容纳K个元素的数组并调整成堆
int i=0;
int*heap=(int*)malloc(sizeeof(int)*k);
for(i=0;i<k;i++)
{
heap[i]=arr[i];
}
for(i=(k-1-1)/2;i>=0;i--)
{
AjustDown(heap,k,i);
}
//将剩余的arrSize-k个元素分别与堆顶元素进行交换,若大于堆顶元素,则进行交换,并调整堆。
for(i=k;i<arrsize;i++)
{
if(arr[i]>heap[0])
{
Swap(&arr[i],&heap[0]);
}
AjustDown(heap;k;0);
}
return heap;
}