堆的应用——在N个数中找到最大的前K个数

        在堆的应用中,有一道很经典的面试题,题目是:“在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个数”,这里只需要建大堆,每个数字和根节点比较。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值