找出N个数据中的最大的K个数据---堆排序

从N个数据中找出最大的K个数据,而且这里有一个限制:内存里存不下所有的N个数据,但是可以存下K个数据。这就让我们打消了用排序的方法来解的念头。

在这里我们使用堆排序来完成。

因为我们只能有K个数据那么大的空间,所以我们建一个K大的堆,将N的前K个数据插入到堆中,然后调整堆。(对于堆结构不了解的可以查看我微博  http://helloleex.blog.51cto.com/10728491/1768758

对于最大的K个数据,我们要怎么找出来呢。我们首先要确定我们是要用大顶堆还是小顶堆。

  •  用大顶堆。用大顶堆的话我们一定可以确定N个数据中最大的1个数据或者多个,但是一定不会是最大K个,因为我们只有K大的内存,所以每次往堆里插入数据同时就要删除一个数据,而删除数据只能删除最大的那一个。到最后大的数据都被Pop完了
  • 用小顶堆。用小顶堆就可以完美的解决这个问题,每次从N个数据中的后N-K个数据插入一个数据到大小为K的堆中替换掉小顶堆的根(最小值)。最后的K个数据就是最大的K个数据。
  • #include"windows.h"
    #include"time.h"
    #include"head.h"
    //堆排序
    void AdjustDown(int* a, size_t size, size_t parent)//下调函数
    {
    	size_t child = parent * 2 + 1;
    	while (child < size)
    	{
    		if (child + 1 < size&&a[child] < a[child + 1])
    			++child;
    		if (a[parent] < a[child])
    		{
    			swap(a[parent], a[child]);
    			parent = child;
    			child = parent * 2 + 1;
    		}
    		else
    			break;
    	}
    }
    
    void HeapSort(int* a, size_t size)
    {
    	//建堆
    	for (int i = (size - 2) / 2; i >= 0; --i)
    		//i不能定义为size_t除法会溢出,翻转成一个很大的数
    	{
    		AdjustDown(a, size, i);
    	}
    	for (size_t i = 0; i < size; ++i)
    	{
    		swap(a[0], a[size - 1 - i]);
    		AdjustDown(a, size - i - 1, 0);
    	}
    }
    
    void FindMaxK(int N,int K)//找出N个数据中最大的K个数据
    {
    	int* arryN = new int[N];
    	int* maxK = new int[K];
    	for (int i = 0; i < N; ++i)
    	{
    		arryN[i] = (rand() % 100);
    	}
    	for (int i = 0; i < N; ++i)
    	{
    		cout << arryN[i] << " ";
    	}
    	cout << endl;
    	for (int i = 0; i < K; i++)
    	{
    		maxK[i] = arryN[i];
    	}
    	for (int i = K; i < N; ++i)
    	{
    		HeapSort(maxK, K);
    		maxK[0] = arryN[i];
    	}
    	for (int i = 0; i < K; ++i)
    	{
    		cout << maxK[i] << " ";
    	}
    }

堆排序的时间效率是nlogn,算是效率比较高的算法了,值得我们去掌握的。

时间: 2024-08-04 19:39:05

找出N个数据中的最大的K个数据---堆排序的相关文章

【数据结构】找出N个数据中最大的前k个数据(利用堆排序)

我们举例,假若从10000万个数里选出前100个最大的数据. 首先我们先分析:既然要选出前100个最大的数据,我们就建立一个大小为100的堆(建堆时就按找最大堆的规则建立,即每一个根节点都大于它的子女节点),然后再将后面的剩余数据若符合要求就插入堆中,不符合就直接丢弃该数据. 那我们现在考虑:确定是该选择最大堆的数据结构还是最小堆的数据结构呢. 分析一下: 若选用最大堆的话,堆顶是堆的最大值,我们考虑既然要选出从10000万个数里选出前100个最大的数据,我们在建堆的时候,已经考虑了最大堆的特性

找出n个字符串中出现次数最多的字符串。

1. 找出n个字符串中出现次数最多的字符串. C/C++: char* find(char **data,int n); Java: String find(String data[]); 说明: 1. data是字符串数组,n是数组中字符串的个数,返回值为出现次数最多的字符串. 2. 若结果有多个,返回任意一个即可 3. 不得使用任何库函数/API,如需使用类似功能, 请自行实现 4. 算法效率尽可能高,尽量少的使用内存空间 5. 必须要有代码注释和算法说明. 例如:data里面的数据是{“p

找出此产品描述中包含N个关键字的长度最短的子串

阿里巴巴笔试题:给定一段产品的英文描述,包含M个英文字母,每个英文单词以空格分隔,无其他标点符号:再给定N个英文关键词,请说明思路并变成实现方法. String extractSummary(String description , String[] keyWords) 目标:找出此产品描述中包含N个关键字的长度最短的子串(20分) W0 W1 W2 W3  Q0 W4 W5 Q1 W6 W7 W8 Q0 W9 Q1 P335 <编程之美>上的参考代码: int nTarget = N + 1

c语言:找出1到4000中,数字的各位数之和能被4整除的数有多少个?

找出1到4000中,数字的各位数之和能被4整除的数,如:745:7+4+5=16,16可以被4整除:28:2+8=10,10不能被4整除:745就是这样的特殊数字,而28不是,求:这样的数字共有多少个? 解: (1)对于4000,4+0+0+0=4,显然4000是满足条件的数字: (2)对于1到3999,我们把每个数字看成4位[][][][]的形式,第一位[]取0到3,后3位取[0][0][0]到[9][9][9],用sum表示4位数字的和: 2.1:若后3位为一个奇数,则第1位取1或3,必定可

找出两个字符串中最长的相同子字符串

//找出两个字符串中最长的相同子字符串 public class Stringdemo { public static void main(String[] args) { String str1 = new String("eeabcde"); String str2 = new String("bcdefabcabcdedegg"); byte[] char1 = str1.getBytes(); byte[] char2 = str2.getBytes();

9.5位操作(三)——给定一个正整数,找出与其二进制表示中1的个数相同,且大小最接近的那两个数

/** * 功能:给定一个正整数,找出与其二进制表示中1的个数相同,且大小最接近的那两个数. * (一个略大一个略小.) */ 三种方法: 方法一:蛮力法 方法二:位操作法 <span style="white-space:pre"> </span>/** * 方法:位操作法 * 思路:获取后一个较大的数 * 1)计算c0和c1.c1是拖尾1的个数,c0是紧邻拖尾1的作坊一连串0的个数. * 2)将最右边.非拖尾0变为1,其位置为p=c1+c0. * 3)将位p

黑马程序员——找出两个字符串中最大的子串

找出两个字符串中最大的子串 </pre><pre name="code" class="java">public class StringMaxString { //找一个字符串的最大子串 public static void main(String[] args) { // TODO Auto-generated method stub String s1="qwerabcdtyuiop"; String s2=&quo

高效的找出两个List中的不同元素

转自同名博文,未知真正出处,望作者见谅 如题:有List<String> list1和List<String> list2,两个集合各有上万个元素,怎样取出两个集合中不同的元素? 方法1:遍历两个集合: package com.czp.test; import java.util.ArrayList; import java.util.List; public class TestList { public static void main(String[] args) { Lis

位运算 找出给定的数中其他数都是两个,有两个是一个的数

题目大意: 给定你n个数, 其中有n-2个数都是两两成对的,有两个是单独出现的,如n = 8, 2 3 2 5 3 6 4 6, 这时候4和5是单独的两个,所以答案就是4,5,其中n的范围是1e6. 思路: 之前做过找一个单独的数的题,那个题是用一个比较巧妙的方法来做的,不过这个也是一类经典问题,用到了强大的位运算,有了那个题的基础再来做这个题就简单了.(附:找一个的题目链接). 刚开始我是用了O(nlogn)的时间复杂度来做的,先排序,然后用类似找一个的方法找出第二个.我觉得对于1e6的数据量