问题的引入:
我们都知道公司有所谓的世界500强,那么全球有如此多的公司,我们要怎样又快又精确的挑出这所谓的500家企业呢?
这就是所谓的 Top - K 问题 即求数据集合中前K个最大的元素或者最小的元素,一般情况下数据量都非常大。
对于该问题,我们能想到的最简单的直接方式就是排序,但是,如果数据量非常的大,排序就不太可取(可能数据都不能一下子全部加载到内存中)。最佳的方法就是用堆来解决,基本思路入下:
1. 用数据集合中前K个元素来建堆
2. 用剩余的 N-K个元素依次与堆顶的元素比较,不满足则替换堆顶元素。
附上代码:
void Top_K(int*a, int n , int k){
int* kminHeap = (int*)malloc(sizeof(int) * k); //动态内存开辟创建数组
for (int i = 0; i <k; i++)
{
kminHeap[i] = a[i]; //将前k个元素先放入数组中
}
for ( int j = (k-1-1)/2; j>= 0; --j)
{
AdjustDown(kminHeap,k,j); //通过向下调整算法建堆
}
for (int i = k; i < n; i++)
{ //和堆顶元素逐个比较并且满足条件进行替换,然后再进行向下调整算法!
if (a[i] > kminHeap[0])
{
kminHeap[0] = a[i];
AdjustDown(kminHeap, k, 0);
}
}
for (int i = 0; i < k; i++)
{
//打印前k元素
printf("%d ", kminHeap[i]);
}
}
同时附上向上调整和向下调整的算法:
void AdjustDown(HPDatatype* a, size_t size,size_t root) {
size_t parent = root;
size_t child = 2 * parent + 1;
while (child < size) {
if (a[child] >a[child +1] && child +1 < size)
{
++child;
}
if (a[parent] > a[child])
{
swap(&a[parent], &a[child]);
parent = child;
child = 2 * parent + 1;
}
else {
break;
}
}
}
void AdjustUp(HPDatatype * a, size_t child) {
size_t parent = (child - 1) / 2;
while (child > 0) {
if (a[child] < a[parent]) {
//交换
swap(&a[child], &a[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
Top-k问题在很多方面都有应用,在处理海量的数据时,Top-K算法能很快的帮我们确定我们要找的前k个最大元素!