在大规模数据处理中,遇到的一类问题是,在海量数据中找出出现频率最高的前K个数,或者从海量数据中找出最大的前K个数,这类问题被称为“top K”问题。
堆的建立
解决top-k问题,可以用建堆方法来处理,选取最高或者最低的数据可以建立小堆来处理。
解决方案:
在海量数据中查找最大的前K个数,可以建立一个以K大小的小堆,小堆特点是堆顶(数组第一个元素)为当前堆结构的最小值,在海量数据中再次查找时,只和堆顶元素进行比较,大于则入堆,这样就能保证堆里元素永远是目前最大的前K个。
void AdjustDown(Datatype* a, size_t n, int root)//向下调整(小堆)
{
int parent = root;
int child = (root * 2 + 1);//左孩子
while (child < n)
{
if (a[child] > a[child+1] && (child+1 < n))//比较左右孩子大小。取较小值
{
++child;
}
if (a[parent] > a[child])
{
Datatype tmp = a[child];
a[child] = a[parent];
a[parent] = tmp;
parent = child;
child = parent * 2 + 1;
}
else
break;
}
}
void TopK(Datatype* a, size_t k, int n)//寻找前K个较大的数(建立小堆)
{
MakeHeap(a, k);
for (int i = k+1; i < n; i++)
{
if (a[i] > a[0])
{
a[0] = a[i];
AdjustDown(a, k, 0);
}
else
continue;
}
}
void TestTopK()
{
int a[1000] = { 0 };
srand(time(0));
int i = 0;
for (i = 0; i < 1000; i++)
a[i] = rand() % 10000;//产生0~10000的数字
//规定数组里某些元素是超出10000的数字,若打印出来不是以下数字,则错误。
a[525] = 10001;
a[89] = 10002;
a[0] = 10003;
a[789] = 10004;
a[23] = 10005;
a[180] = 10006;
a[999] = 10007;
a[666] = 10008;
a[483] = 10009;
a[359] = 10010;
TopK(a, 10, sizeof(a) / sizeof(a[0]));
for (i = 0; i < 10; i++)
{
printf("%d ", a[i]);
}
}