求最大的K个值


             最近在看一个题目:给定一个无序的整型数组,求出其中最大的K个值。

    这个题的解法很多,最普遍的就是排序,时间复杂度就是O(nlogn)+O(n)。

    还可以根据快速排序的思想,分治与递归的求解最大的K个值。基本思想是:在每一次排序后,会有一个数字到达了它的有序的位置,这个数字之前所有的元素都小于它,它后面的所有的元素都大于它。可以用Sa表示前面的元素,Sb表示后面的元素。如果K>Num(Sb)(Num表示数组中元素的个数),那么就输出Sb,然后递归在Sa中寻找剩余的K-Num(Sb)。如果K<Num(Sb),那么就递归在Sb中寻找K个最大的值。这样递归下去,不断把问题分解成更小的问题,平均时间复杂度为O(N*logK),算法得到了进一步改进。

以下是这个思想的代码:

void fun(int data[],int low,int hight,int k)
{
	
	int i = low;
	int j = hight;
	int x = data[low];
	
	while(j > i)
	{
		while(data[j] > x && j > i)
			j--;
		if(i < j)
		{
			data[i] = data[j];
			i++;
		}

		while(data[i] < x && j > i)
			i++;
		if(i < j)
		{
			data[j] = data[i];
			j--;
		}
	}
	data[i] = x;
	int pos = i;

	if(k > hight - pos )
	{
		for(int n = pos + 1; n <= hight; n++)
			cout << data[n] << " ";
		fun(data,low,pos,k-hight+pos);
	}
	else if(k < hight - pos)
	{
		fun(data,pos+1,hight,k);
	}
	else
	{
		for(int n = pos+1; n <= hight; n++)
			cout << data[n] << " ";
	}

}



    如果,数组很大时,比如数组有1亿个元素呢,如果还用以上算法就会显得非常的慢。我们可以用堆来求其中的最大的K个值。

    思想:构造一个小根堆,因为根是最小的,然后将原数组中剩余的元素与堆的根比较,如果heap_value > data[i],那么继续遍历数组, 如果heap_value < data[i],那么将heap_value的值改为data[i],并调整堆,使新堆满足小根堆。这样只需遍历原数组一遍就可以找到K个最大值,这K个最大的值就存储在堆中。

    顺便回忆一下小根堆是怎么来构建和调整的。设堆的节点数为n,因为堆是一个完成二叉树,那么最后一个非叶节点就是n/2。从这个节点开始来构建堆。设当前节点为p,那么q = 2 * q + 1,q就是左子树,q+1就是右子树。如果左子树或者右子树的值比父节点的值小,那么和父节点交换。然后看子树的子树是否需要调整,如果不需要调整,那么p--,开始向上走,这样最后便得到一个小根堆,大根堆同理。

下面是求K个最大值,用小根堆解的代码:

void swap2(int &a,int &b)
{
	int tmp = a;
	a = b;
	b = tmp;
}
void CreateHeap(int data[],int K)
{
	int p = K/2 - 1;
	
	while(p >= 0 && p < K)
	{
		int q = 2 * p + 1;
		if(q < K)
		{
			if(q < K - 1 && data[q+1] < data[q])
				q = q + 1;
			if(data[q] < data[p])
			{
				swap2(data[p],data[q]);
				int n = 2 * q + 1;
				if(n < K)
				{
					if((data[q] > data[n] )||((n < K-1) && (data[q] > data[n+1])))
					{
						p = q;
					}
				}

				else
					p--;
			}
			else
				p--;
		}
		
		
	}
}
void FindMaxK2(int data[],int len,int K)
{
	int *heap = new int[K];
	// 初始化堆
	for(int i = 0;i < K; ++i)
	{
		heap[i] = data[i];
	}
	// 调整成小根堆
	CreateHeap(heap,K);
	
	// 开始将剩余元素与堆根比较,并调整堆
	for(int i = K; i < len; ++i)
	{
		int X = data[i];
		if(X > heap[0])
		{
			heap[0] = X;
			CreateHeap(heap,K);
		}
	}

	for(int i = 0; i < K; ++i)
		cout << heap[i] << " ";
	delete []heap;
	heap = 0;

}



  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值