20170927_利用大根堆求出最小的K个数

20170927_利用大根堆求出最小的K个数


当数据量比较大而内存一次性装不下的时候,想要对求出数据中最小的K个数,
则可以采用大根堆,维护一个含有K个数的大根堆,这个堆中的所有元素就是所求。
首先,读入K个数创建一个大小为K的大根堆,然后依次读入后序的数据,依次与大根堆的堆顶元素比较,
若大于堆顶元素,则直接抛弃该元素、读入下一个元素。
若小于堆顶元素,则该元素属于最小的K个元素之一,需要用它来替换堆顶元素,然后再从堆顶元素开始维护这个大根堆。
直到所有元素都比较完为止,这个堆中的所有元素就是所求。


//大根堆的应用_数组中查找最小的K个数
/*
当数据量比较大而内存一次性装不下的时候,想要对求出数据中最小的K个数,
则可以采用大根堆,维护一个含有K个数的大根堆,这个堆中的所有元素就是所求。
首先,读入K个数创建一个大小为K的大根堆,然后依次读入后序的数据,依次与大根堆的堆顶元素比较,
若大于堆顶元素,则直接抛弃该元素、读入下一个元素。
若小于堆顶元素,则该元素属于最小的K个元素之一,需要用它来替换堆顶元素,然后再从堆顶元素开始维护这个大根堆。
直到所有元素都比较完为止,这个堆中的所有元素就是所求。
*/

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include<numeric>
#include<functional>
using namespace std;
//建立大根堆——>自上而下的重新调整堆结构
void Sift(int r[], int k, int m)
{
	int i=k;		//需要调整的节点是k=i
	int j=2*i;		//节点j 是节点i 的左孩子节点
	int temp=0;		//堆中最后一个结点的编号是m(m=n),节点总个数
	while(j<=m)		//筛选还没有进行最后一个节点时
	{
		if(j<m && r[j]<r[j+1])		//比较节点i的左右孩子,j为较大者
			++j;
		if(r[i]>r[j])				//如果根节点i值已经大于左右孩子中的最大值,直接退出即可
			break;
		else						//否则,需要交换根节点和左右孩子中的最大值的那个节点
		{
			temp=r[i];
			r[i]=r[j];
			r[j]=temp;
			i=j;					//被筛节点位于原来节点j的位置
			j=2*i;					//自上向下调整,i始终是被筛的节点
		}
	}
}
//建立大根堆——>循环建立
void CreatBigHeap(int r[], int n)
{
	for(int i=n/2; i>=1; --i)		//共n个元素,从最后一个非叶子节点开始筛
		Sift(r, i, n);				//每次筛的节点是i
}
//主函数
int main(void)
{
	int k=0;
	cin>>k;							//最小的K个数
	int r[]={1,2,8,7,3,4,6,5};
	int *B=new int(k);
	for(int i=0; i<k; ++i)
		B[i]=r[i];
	
	CreatBigHeap(B, k);

	for(int i=k; i<sizeof(r)/sizeof(r[0]); ++i)
	{
		if(r[k]>=B[i])			//若大于堆顶元素
			continue;
		else					//若小于堆顶元素
		{
			B[i]=r[i];
			Sift(B, 1, k);
		}
	}
	system("pause");
	return 0;
}


  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值