求数组前K个大的数
我们举例,假若从10000万个数里选出前100个最大的数据。
首先我们先分析:既然要选出前100个最大的数据,我们就建立一个大小为100的堆(建堆时就按找最大堆的规则建立,即每一个根节点都大于它的子女节点),然后再将后面的剩余数据若符合要求就插入堆中,不符合就直接丢弃该数据。
那我们现在考虑:确定是该选择最大堆的数据结构还是最小堆的数据结构呢。
分析一下:
若选用最大堆的话,堆顶是堆的最大值,我们考虑既然要选出从10000万个数里选出前100个最大的数据,我们在建堆的时候,已经考虑了最大堆的特性,那这样的话最大的数据必然在它顶端。假若真不巧,我开始的前100个数据中已经有这10000个数据中的最大值了,那对于我后面剩余的10000-100的元素再想入堆是不是入不进去了!!!所以,选用最大堆从10000万个数里选出前100个最大的数据只能找出一个,而不是100个。
那如果选用最小堆的数据结构来解决,最顶端是最小值,再次遇到比它大的值,就可以入堆,入堆后重新调整堆,将小的值pass掉。这样我们就可以选出最大的前K个数据了。言外之意,假若我们要找出N个数据中最小的前k个数据,就要用最大堆了。
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std; #include<assert.h> void AdjustDown(int* a, int parent, int size)
{
int child = 2 * parent + 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 = 2 * parent + 1;
}
else
{
break;
}
}
} void Print(int* a, int size)
{
cout << "前k个最大的数据:" << endl;
for (int i = 0; i < size; i++)
{
cout << a[i] << " ";
}
cout << endl;
} int* HeapSet(int*a,int N,int K)
{
assert(a);
assert(K > 0);
int* arr = new int[K];
//将前K个数据保存
for (int i = 0; i < K; i++)
{
arr[i] = a[i];
} //建堆
for (int i = (K-2)/2; i >=0; i--)
{
AdjustDown(arr,i,K);
} //对剩余的N-K个元素比较大小
for (int i = K; i < N; i++)
{
if (arr[0]<a[i])
{
arr[0] = a[i];
AdjustDown(arr, 0, K);
}
} return arr;
delete[] arr;
} void Test()
{
int arr[] = { 12, 2, 10, 4, 6, 8, 54, 67, 25, 178 };
int k = 5;
int* ret = HeapSet(arr, sizeof(arr) / sizeof(arr[0]), k);
Print(ret, k);
} int main()
{
Test();
system("pause");
return 0;
}
由此可以看出,时间复杂度为:K+(K-2)/2*lgn+(N-K)*lgn --> O(N)
空间复杂度为:K-->O(1)。
求数组前K个大的数的更多相关文章
- MATLAB寻找数组前k个大值
有时候我们需要寻找数组的前k个大值并按照顺序输出, 在C语言可以通过快速排序等算法,快速求得,这里用matlab写了一个比较简单实用的程序(适用于数组长度不是特别大的情况). function [va ...
- [csu/coj 1080]划分树求区间前k大数和
题意:从某个区间内最多选择k个数,使得和最大 思路:首先题目给定的数有负数,如果区间前k大出现负数,那么负数不选和更大,于是对于所有最优选择,负数不会出现,所以用0取代负数,问题便转化为区间的前k大数 ...
- 无序数组中第Kth大的数
题目:找出无序数组中第Kth大的数,如{63,45,33,21},第2大的数45. 输入: 第一行输入无序数组,第二行输入K值. 该是内推滴滴打车时(2017.8.26)的第二题,也是<剑指of ...
- 输出数组里面第N大的数
好像有些大公司出过面试题:找出数组里面第N大的数,当然有点变化,但本质部分是这样的. 要求是不能排序,时间复杂度不能超过O(n^2) 思路很多,我暂时就只会快排衍生的那种.如果对快速排序不太熟悉了,建 ...
- 快速排序及查找第K个大的数。
本文提供了一种基于分治法思想的,查找第K个大的数,可以使得时间复杂地低于nlogn. 因为快排的平均时间复杂度为nlogn,但是快排是全部序列的排序, 本文查找第k大的数,则不必对整个序列进行排序.请 ...
- 认真对待每一道算法题 之 两个排序好的数组寻找的第k个大的数
转载博客:http://www.cnblogs.com/buptLizer/archive/2012/03/31/2427579.html 题目意思:给出两个排好序的数组 ,不妨设为a,b都按升序排列 ...
- [经典] 在未排序数组中返回topK大的数
解法一,排序 先从大到小快排,然后扫前K个返回 时间复杂度:O(NlogN),空间复杂度O(1) 解法二,优先队列 前K个放入优先队列中,与最小堆顶元素比较大小,若大于则删除堆顶并插入:否则跳过 时间 ...
- (算法)Partition方法求数组第k大的数
如题,下面直接贴出代码: #include <iostream> using namespace std; int Partition(int* A,int left,int right) ...
- 【RMQ问题】求数组区间最大值,NYOJ-1185-最大最小值
转自:http://blog.csdn.net/lilongherolilong/article/details/6624390 先挖好坑,明天该去郑轻找虐 RMQ(Range Minimum/Max ...
随机推荐
- 赞!这款国产的SSH工具,好用到爆!
之前分享 MobaXterm 时 有小伙伴留言说到了 FinalShell 我本来是一脸蒙蔽的 网上搜了一下 它们家的官网 打开官网 我一度怀疑自己进错了网站 简单(jianlou)的排版 像极了上个 ...
- 基于Django的Rest Framework框架的版本控制
本文目录 一 作用 二 内置的版本控制类 三 局部使用 四 全局使用 五 示例 源码分析 回到目录 一 作用 用于版本的控制 回到目录 二 内置的版本控制类 from rest_framework.v ...
- oracle中如何更改一个表的一个字段属性(名称,类型)
修改字段的属性,名称方法 --修改某一个字段的类型,当该字段不为null时alter table 表名add 字段NUMBER(11,0) default 0 not null;--添加表一个字段 A ...
- Flume笔记
flume自定义拦截器:实现Interceptor接口flume自定义source:继承AbstractSourceflume自定义sink:继承AbstractSink azkaban:任务调度工具 ...
- Windows Terminal (Preview)治好了cmd,powershell的癌症
前言 话说n年前,我想开发一款powershell麻将游戏,但是发现命令行下无法显示麻将牌这种特殊符号. 经过研究发现,这是4字节的utf16le字符串.而powershell依赖的渲染引擎,只能渲染 ...
- dubbo入门教程-从零搭建dubbo服务
[原创 转载请注明出处] 本文是学习了dubbo之后自己手动写的,比较通俗,很多都是自己学习之后的理解,写的过程中没有参考任何文章. 另外dubbo也有官方文档,但是比较官方,也可以多看看dubbo的 ...
- JVM的监控工具之jvisual
VisualVM(All-in-One Java Trouble shootingTool)是到目前为止随JDK发布的功能最强大的运行监视和故障处理程序,并且可以预见在未来一段时间内都是官方主力发展的 ...
- Beats Elastic中的Auditbeat使用介绍
Auditbeat使用介绍 Auditbeat是一种轻量级的数据收集器,您可以将其安装在服务器上,以审核系统上用户和进程的活动. 例如,您可以使用Auditbeat从Linux Audit Frame ...
- MySQL5.7增量备份恢复全实战
一. 简介 1. 增量备份 增量备份是指在一次全备份或上一次增量备份后,以后每次的备份只需备份与前一次相比增加或者被修改的文件.这就意味着,第一次增量 备份的对象是进行全备后所产生的增加和修改的文件; ...
- Python基础21
对轴0,轴1,“axis”轴的理解很关键