第五题(查找最小的k 个元素)

5.查找最小的k 个元素
题目:输入n 个整数,输出其中最小的k 个。

例如输入1,2,3,4,5,6,7 和8 这8 个数字,则最小的4 个数字为1,2,3 和4。

思路:维护一个k个元素的最大堆,初始元素取n个整数的前k个即可,遍历剩下的n-k个整数,取出每一个整数和最大堆的根节点也就是k个元素的最大值比较,若这个整数小于该根节点,说明根节点肯定不是最小的k个值里面的一个,直接用这个整数替换根节点并重新调整堆,这样堆里始终存储的是遍历到的整数里最小的k个,重复上述过程直到遍历结束,这样就获得了n个元素里面最小的k个。初始化堆的时间复杂度为O(klog(k))【更正,建堆过程的复杂度应该为O(k)】,后面替换根节点后重新调整需要的总的时间复杂度为O(k+nlog(k)),总的时间复杂度为O(nlog(k))。

C++ STL里面的set基于红黑树实现,在自定义set的排序函数为降序排列后,我们可以很方便的使用set来解决这个问题。

也可以自己实现堆处理。

这里给出两种实现的代码:

namespace MS100P_5
{
	//采用STL的容器multiset
	void findKleastNum(int data[], int length, int k, int result[])
	{
		multiset<int, greater<int>> dataHeap;
		int i;
		for (i = 0; i < k; i++)
			dataHeap.insert(data[i]);
		for (i = k; i < length; i++)
		{
			if (data[i] < *dataHeap.begin())
			{
				dataHeap.erase(dataHeap.begin());
				dataHeap.insert(data[i]);
			}
		}
		multiset<int>::iterator iter = dataHeap.begin();
		for (i = 0; i < k; i++)
		{
			result[i] = *iter;
			iter++;
		}
		 
	}
	//自己实现堆操作
	//最大堆堆插入操作
	void insert(int data[], int i)  //data 待插入堆i,插入的位置  value 插入的值
	{
		int j,temp;
		j = (i - 1) / 2;
		temp = data[i];
		while (j >= 0 && i != 0)
		{
			if (data[j] < temp)
				data[i] = data[j];
			else
				break;
			i = j;
			j = (i-1) / 2;
		}
		data[i] = temp;
	}

	void insert2(int heap[], int i, int value)
	{
		//保险起见,可以增加i和数组大小的比较
		for (; i>0 && heap[(i - 1) / 2]<value; i = (i - 1) / 2)
			heap[i] = heap[(i - 1) / 2];
		heap[i] = value;
	}

	
	void adjustHeap(int data[], int length, int i)	//从i开始向下调整堆
	{
		int j, temp;
		temp = data[i];
		j = 2 * i + 1;	//左孩子
		while (j < length)
		{
			if ((j + 1 < length)&&data[j + 1] > data[j])
				j++;
			if (data[j]>temp)			//又犯了低级错误,把temp写成了a[j],浪费时间呐
				data[i] = data[j];
			else
				break;
			i = j;
			j = 2 * i + 1;
		}
		data[i] = temp;
	}
	void findKleastNum2(int data[], int length, int k, int result[])
	{
		int i;
		for (i = 0; i < k; i++)			//建立最大堆
		{
			insert2(result, i,data[i]);
		}

		for (i = k; i < length; i++)
		{
			if (data[i] < result[0])
			{
				result[0] = data[i];
				adjustHeap(result, k, 0);
			}
		}
	}
	
	void test()
	{
		int data[20], result[5];
		createArray(data, 20);
		printArray(data,20);
		findKleastNum(data,20,5,result);
		printArray(result, 5);
		findKleastNum2(data, 20, 5, result);
		printArray(result, 5);
	}
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值