查找N个数中第K大的数

方法一:将一组数放入数组中,升排序。并返回第 ( length - k )个元素
这里消耗的时间就是排序用的时间,用快速排序则为:O( N log N )


代码:

	/**
* 先排序后获取
* @return
*
* Date	  :2012-7-4
* Author :GongQiang
*/
public int sortThenGet( int k ){
Collections.sort( list );
return list.get( list.size() - k );
}


方法二:构造一个 K 长度的数组,将前K位数复制过来并排序(降序)。然后依次将 K+1 到 N 位的数比较并插入 K 长度的数组中。返回最后一个即可。

这时间度为:O( N*K ) 如果 K = N/2  则复杂度为 O( N*N )


代码:

	/**
* 先取出前K个数排序,再从后面依次插入
* @param k
* @return
*
* Date	  :2012-7-4
* Author :GongQiang
*/
public int kSortThenCompare( int k ){
List<Integer> result = new ArrayList<Integer>( k );
for( int i=0 ; i<k ; i++ ){
result.add( list.get(i) );
}
//前K位数,按照从大到小排序
Collections.sort( result, new Comparator<Integer>(){
public int compare(Integer o1, Integer o2) {
if( o1 > o2 ){
return -1;
}
if( o1< o2 ){
return 1;
}
return 0;
}
});
// 后 K+1 位数与前面的有序数组比较,插入适当的位置
for( int i=k ; i<list.size() ; i++ ){
int j = k-1;
while( j>=0 && list.get(i) > result.get(j) ){
j--;
}
if( 0<=j && j<k-1 && list.get(i) < result.get(j) ){
result.add( j+1, list.get(i) );
}
else if( j==-1 ){ //结束条件是 j==-1
result.add( 0, list.get(i) );
}
}
return result.get( k-1 );
}


方法三:将 N 个数构造成一个“大堆”,然后删除堆的根 K 次,最后一次即为结果。

 构造堆的最坏用时:O( N )

每次删除根用时:O( log N )

则中的运行时间为: O( N + k*log N )

如果 K = O(  N/ log N ) ,则总共用时就是构造堆的时间,即 O( N )

如果 K 很大,则总时间为 O( K* log N)

如果 K = N/2,则总时间为Θ( N*log N )


代码:

	/**
* 先构建一个堆,然后获取
* @param k
* @return
*
* Date	  :2012-7-4
* Author :GongQiang
*/
public int buildHeapThenGet( int k ){
PriorityQueue<Integer> heapQueue = new PriorityQueue<Integer>( NUMBER_COUNT, 
new Comparator<Integer>(){ //这里是取第K大的元素,因而要改变排序规则
public int compare(Integer o1, Integer o2) {
if( o1 > o2 ){
return -1;
}
if( o1< o2 ){
return 1;
}
return 0;
}
});
for( int i=0 ; i<list.size() ; i++ ){
heapQueue.add( list.get(i) );
}
int result=0;
for( int i=0 ; i<k ; i++ ){
result = heapQueue.remove();
}
return result;
}


方法四:思路和方法二一样,只不过用堆来实现。

构造堆的时间:O( K )

处理每个其余元素的时间:O( 1 )

检测是否进入堆的时间:O( log K )

总时间:O( K + (N-K)*log K ) = O( N* log K )

该算法找出中位数的时间界面:Θ( N*log N )

注意:这里使用优先队列提供的堆来操作,这样

检测的时间为O( log K )

删除的时间为O( log K )

插入的时间为O( log K )

所以,这里的代码时间复杂度比单纯在堆上操作要多很多。


代码:

	/**
* 前K个数构造一个堆,然后进行比较插入
* @param k
* @return
*
* Date	  :2012-7-4
* Author :GongQiang
*/
public int heapOfFistKThenSert( int k ){
PriorityQueue<Integer> heapQueue = new PriorityQueue<Integer>( k );
for( int i=0 ; i<k ; i++ ){
heapQueue.add( list.get(i) );
}
for( int j = k ; j<list.size() ; j++ ){
int queueLength = k;
int flag = 0;
while( queueLength >0 ){
if( heapQueue.peek() < list.get(j) ){
flag =1;
break;
}
queueLength--;
}
if( flag == 1 ){
heapQueue.poll();
heapQueue.offer( list.get(j) );
}
}
return heapQueue.peek();
}

四种算法在 10 万个数值中,查找第100大,1000大,10000大实际用时

先排序在获取:
用时间:69547064, 100大数:99903985
用时间:64447309, 1000大数:98963233
用时间:63601693, 10000大数:89862625
先排序前K个数,然后插入,最后获取:
用时间:14299865, 100大数:99903985
用时间:94025432, 1000大数:98963233
用时间:4053122244, 10000大数:89857698
先构建一个堆,然后获取:
用时间:29191262, 100大数:99903985
用时间:11743673, 1000大数:98963233
用时间:21491442, 10000大数:89862625
先构建一个堆(前K个数),依次比较插入,最后获取:
用时间:199040953, 100大数:99903985
用时间:1786736869, 1000大数:98963233
用时间:11739682175, 10000大数:89862625

可以看出,方法三最优。

方法五:随机选择(参考快速排序的思想)

	/**
* 随机选择
* @param list
* @param start
* @param end
* @param i
* @return
*
* Date	  :2012-10-25
* Author :GongQiang
*/
int randomSelect( List<Integer> list, int start, int end, int i ){
if( start == end ){
return list.get(start);
}
int q = randomPartition(list, start, end);
int k = end - q + 1;
if( i == k ){
return list.get( q );
}
else if( i<k ){
return randomSelect(list, q+1, end, i);
}
else{
return randomSelect(list, start, q-1, i-k);
}
}
private int randomPartition( List<Integer> list, int start, int end ){
int i = (int)(random.nextFloat()*( end-start )) + start;
swap( list, i, end );
return partition(list, start, end);
}
private int partition( List<Integer> list, int start, int end ){
int temp = list.get(end);
int i = start - 1;
for( int j=start; j<end; j++ ){
if( list.get(j) <= temp ){
i++;
swap( list, i, j);
}
}
swap( list, i+1, end);
return i+1;
}
private void swap( List<Integer> list, int i, int j ){
int temp = list.get(i);
list.set(i, list.get(j));
list.set(j, temp);
}

运行性能比较(一百万中查询):

先排序在获取:
用时间:1073446509, 100大数:99991468
用时间:1086298487, 1000大数:99897550
用时间:995448554, 10000大数:98988059
用时间:996302124, 550000大数:45011888
先构建一个堆,然后获取:
用时间:98659237, 100大数:99991468
用时间:92088339, 1000大数:99897550
用时间:114273553, 10000大数:98988059
用时间:1590825451, 550000大数:45011888
随机选择
用时间:113330378, 100大数:99991468
用时间:121606562, 1000大数:99897550
用时间:123834509, 10000大数:98988059
用时间:231643029, 550000大数:45011888

可以看出,【随机选择】性能很稳定,而且较优!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/497826.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

美国科学院学报:如何在竞争激烈的环境下维持稳定的群体

行为决策演化示意图。最上面一行是混合群体&#xff0c;下面两行是网络群体。相比于混合群体&#xff0c;网络促使合作者聚集成团簇&#xff0c;但是惩罚的加入将破坏合作环境。来源&#xff1a;中国科学院西安光机所李学龙研究员同合作者在数据驱动的行为决策研究方面取得阶段…

linux文本处理脚本题,Linux文本处理工具sed练习题

1、使用sed命令打印出ifconfig ens33的ip地址解:(1)ifconfig ens33 | sed -n 2p | sed s/.*inet // | sed s/netmask.*//(2)ifconfig ens33 | sed -n 2p | sed -r s/.*inet (.*)netmask.*/\1/(3)ifconfig ens33 | sed -r -n 2s/.*inet (.*)netmask.*/\1/p2、使用sed命令打印出系…

全球首个Magic Leap One体验:吓到你不敢进房间

来源&#xff1a;智东西概要&#xff1a;业内备受关注的AR技术公司Magic Leap&#xff0c;在获得19亿美元融资历经七年之后&#xff0c;终于放出其第一款头盔产品Magic Leap One&#xff0c;很快在科技圈、VR圈引起刷屏式关注。昨夜&#xff0c;业内备受关注的AR技术公司Magic …

ftp+linux+使用webdav,群晖-win/mac/nfs ftp tftp webdav文件服务的概念及设置

应用程序级别WebDAV 是一个 HTTP 的扩充服务&#xff0c;可让用户编辑和管理存储在远程服务器上的文件。通过 Synology DiskStation Manager 的 WebDAV 服务&#xff0c;支持 WebDAV 的客户端程序(如 Windows 资源管理器、Mac OS Finder、Linux 资源管理器)将能够远程访问 Syno…

二叉堆

满足如下结构性和堆序性&#xff0c;即为二叉堆。 结构性质&#xff1a;堆是一棵被完全填满的二叉树&#xff0c;有可能的例外是在底层&#xff0c;底层上的元素从左到右填入。这样的树称为完全二叉树。 容易证明&#xff0c;一棵高为 h 的完全二叉树有 2h 到 2h1-1 个节点。这…

linux模式匹配运算符,linux之正则表达式

文件查找的需要&#xff1a;grep:(GLOBAL Research) 根据模式(网)去搜索文本&#xff0c;而后将符合模式的文本行显示出来。【部分匹配&#xff0c;显示时显示一行】Pattern&#xff1a;模式。(文本字符以及正则表达式元字符组合而成的匹配条件)例子&#xff1a;grep‘root’/e…

伯克利AI研究院解析「反向课程学习」,改善「强化学习智能体」并应用于机器人技术

原文来源&#xff1a;arXiv作者&#xff1a;Wieland Brendel、Jonas Rauber、Matthias Bethge「雷克世界」编译&#xff1a;嗯~阿童木呀、哆啦A亮众所周知&#xff0c;强化学习&#xff08;RL&#xff09;是一种强大的技术&#xff0c;它能够解决诸如移动&#xff08;locomotio…

《Science》评选2017年十大科学突破,看看有哪些吧!

来源&#xff1a;材料科学与工程概要&#xff1a;美国《科学》杂志21日公布了其评选出的2017年十大科学突破&#xff0c;人类首次观测到双中子星并合事件被选为头号科学突破。美国《科学》杂志21日公布了其评选出的2017年十大科学突破&#xff0c;人类首次观测到双中子星并合事…

linux 第三章红帽子,红帽子 Linux_命令全解

118.Ctrlz 把程序放入后台运行-暂停状态&#xff0c;Ctrlc 终止进程&#xff0c;整洁关闭119.jobs 作业列表120.bg [%作业号] 后台恢复运行121.fg [%作业号] 前台恢复运行122.(date;who | wc -l ) >> logfile 聚集命令()&#xff0c;生成subshell全部发送123.echo $? 保…

PL/SQL-FOR UPDATE 与 FOR UPDATE OF的区别

数据库 oracle for update of 和 for update区别 select * from TTable1 for update 锁定表的所有行&#xff0c;只能读不能写 2 select * from TTable1 where pkid 1 for update 只锁定pkid1的行 3 select * from Table1 a join Table2 b on a.pkidb.pkid for u…

2017年深度学习重大研究进展全解读

来源&#xff1a;机器之心概要&#xff1a;想知道哪些深度学习技术即将影响我们的未来吗&#xff1f;本文将给你作出解答。2017 年只剩不到十天&#xff0c;随着 NIPS 等重要会议的结束&#xff0c;是时候对这一年深度学习领域的重要研究与进展进行总结了。来自机器学习创业公司…

linux管道符加空格吗,管道符,作业控制,变量以及变量配置文件

一、管道符前面已经提过过管道符 “|”, 就是把前面的命令运行的结果丢给后面的命令。# cat 1.txt | wc -l //显示1.txt文件行数二、作业控制当运行进程时&#xff0c;你可以使它暂停(按CtrlZ组合键)&#xff0c;然后使用fg(foreground的简写)命令恢复它&#xff0c;或是利用bg…

PL/SQL 连接配置

PLSQL连接oracle数据库配置 方法一&#xff1a; 1&#xff09;点击Net Configuration Assistant 2) 在弹出的对话框中选择本地Net服务名配置&#xff0c;点下一步 3&#xff09; 在服务名配置对话框中选择添加&#xff0c;点下一步 4&#xff09;在如下对话框中填写要访问的ora…

自动驾驶汽车硬件与软件技术介绍

来源&#xff1a;知乎概要&#xff1a;本文详细介绍了自动驾驶汽车的硬件和软件&#xff0c;以及所需要做的准备工作&#xff0c;每个研发者或者准备投身于无人驾驶领域的人都应该好好看一下。全球有数不清的公司在忙着研发自动驾驶汽车&#xff0c;他们的产品也千奇百怪&#…

linux数组随机数,随机数与数组

随机数数组变量清屏时间延迟静态网站HTML随机数srand()函数用于播种函数头文件: stdlib.h函数定义: void srand(unsigned int seed)函数功能:设置随机数种子函数说明:通常可以用getpid(获取当前进程的进程识别码)或者time(NULL)(获取当前系统的时间信息)来充当种子&#xff0c;…

DeepMind 的2017:有 AlphaGo,更有社会责任

来源&#xff1a;AI科技评论概要&#xff1a;DeepMind 相信 AI 在更复杂的问题上也能起到同样的作用&#xff0c;它可以是科学技术工具&#xff0c;也可以是人类创造力的倍增器。AlphaGo 团队现在已经把注意力转向了另一组宏伟的目标&#xff0c;DeepMind 自己也希望这些研究人…

脏读、不可重复读和幻读

1. 脏读 &#xff1a;脏读就是指当一个事务正在访问数据&#xff0c;并且对数据进行了修改&#xff0c;而这种修改还没有提交到数据库中&#xff0c;这时&#xff0c;另外一个事务也访问这个数据&#xff0c;然后使用了这个数据。2. 不可重复读 &#xff1a;是指在一个事务内…

c++语言中break的作用,C++ break和continue用法详解

用于 switch 中的 break 语句也可以放在循环中&#xff0c;当遇到 break 时&#xff0c;循环立即停止&#xff0c;程序跳转到循环后面的语句。以下是一个带有 break 语句的循环示例。程序段中的 while 循环看起来要执行 10 次&#xff0c;但 break 语句导致它在第 5 次迭代后即…

2018年人工智能13大预测

来源&#xff1a;英伟达概要&#xff1a;2017 年人工智能领域取得了许多里程碑式的成果。那么&#xff0c;以后人工智能又会如何发展呢&#xff1f;2017年被《华尔街日报》、《福布斯》和《财富》等刊物称为“人工智能之年”。各种深度学习在线课程不断推出&#xff0c;接受相关…

ORACLE 多版本读一致性

先来看看这段代码&#xff1a;while s in (select * from table1) loopinsert into table1 values(s.field1,s.field2,s.field3,s.field4,s.field5);end loop;如果是SQL server的开发人员&#xff0c;看到这段代码&#xff0c;肯定会摇头&#xff1a;这段代码有问题&#xff0c…