在堆的应用中,有一道很经典的面试题,题目是:“在100w个数中找到最大的100个数”。对于堆的相关知识和堆实现的代码在我的前2前博客中都有详解,对于这道题会有很大的帮助。
让我们来剖析一下这道题,我们先建立两个数组,一组数组arr的大小为N,另一组数组topk的大小为K,显然,我们要对topk建堆。找最大的前K个数字自然要建立小堆。则根节点(即topk[0])是K个数字中最小的一个。再把每个数字和根节点比较,如果当前数字比根节点的数字大的话,那么用当前数字替代根节点,同时新根节点向下调整,使得新根节点还是topk数组中最小的数字。反复即可,直到N个数字全部比较完。
为了便于测试,N,K都选了较小的数字,以便读者们阅读。
下面是代码的实现
“test.cpp”
<strong><span style="font-size:18px;">#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
#define N 1000
#define K 20
//向下调整
void AdjustDown(int* a,size_t size,int parent)
{
int child = 2 * parent + 1;
while (child < size)
{
//建立小堆
if (((child + 1) < size)
&&(a[child+1] < a[child]))
{
child++;
}
if (a[child] < a[parent])
{
swap(a[child],a[parent]);
parent = child;
child = 2 * parent + 1;
}
else
{
break;
}
}
}
void GetTopK(int* arr,int* topk,int n,int k)
{
for (size_t i = 0;i < k;i++)
{
topk[i] = arr[i];
}
//非叶子节点向下调整
for (int i = (k-2)/2;i >= 0;i--)
{
//topk建堆
AdjustDown(topk,k,i);
}
for (size_t i = k;i < n;i++)
{
if (arr[i] > topk[0])
{
topk[0] = arr[i];
AdjustDown(topk,k,0);
}
}
}
void Test()
{
//在1000个数中找出最大的前20个数
int arr[N] = {0};//初始化数组
int topk[K] = {0};
for (size_t i = 0;i < N;i++)
{
arr[i] = i;
}
arr[50] = 2542;
arr[100] = 3415;
arr[150] = 4685;
arr[200] = 1185;
GetTopK(arr,topk,N,K);
for (size_t i = 0;i < K;i++)
{
cout<<topk[i]<<" ";
}
cout<<endl;
}
int main()
{
Test();
system("pause");
return 0;
}</span></strong>
同理,如果是“100w个数中找最小的前K个数”,这里只需要建大堆,每个数字和根节点比较。