如何轻松将上亿的数据玩弄于股掌之中?


在日常生活中,我们经常会遇到排序问题


  • 在打扑克牌的时候,原本拿到手上的牌是乱序的,我们会按照自己喜好的顺序一张一张排好手上的牌,最后看起来是顺眼的。比如小智打扑克牌会将自己手上的牌排成这样:


小智排了一下手上的牌,这次手上的牌还不错


  • 摄影师给毕业的同学们拍照片,要求同学们站好队形,然后要求中间高,两边低的方式排队。如果摄影师发现某个同学的高度跟旁边的同学不协调,这个同学必须马上调整自己的位置,最后是一派整齐的景象


摄影师:嗯,你们排得不错


  • 经常泡图书馆的泡友,会发现有很多志愿者会帮忙整理图书位置。每一本书的书背上面都有一张标签,书架上的图书需要按照标签上的编号排好顺序,这样泡友才能快速找到想要的图书。


小智的书架,是不是还算整齐?


这些例子就是排序问题了。排序问题不仅在生活中常见,在IT届也常见。据说,某科技公司在做一个项目时遭遇大量排序问题,运算速度奇慢,项目经理非常头痛,为招收能制伏排序问题的人才,干脆总结成了一道题目(没想到这道题日后竟成为IT面试届的经典)。这道题就是:


如何在一亿个数当中找到最大的10000个数?


如果让小智手工去找这些数,用一辈子的时间可能还不够。当然我们要用计算机来算,我们不仅要考虑,计算机能够如何找到这10000个最大的数,更重要的是找到这10000个数的时间越短越好


方法一:重复寻找法


我们可以先用最直观的方式来做这道题目,起个名字叫重复寻找法


第1步:我们先在这一亿个数当中,寻找到最大的那个数字,把它记录下来。


第2步:从这一亿个数字中,剔除这个最大的数字


第3步:重复执行第1步和第2步,直至记录下来10000个数字。记录下来的结果即为所求。


以挑苹果为例重复寻找法就好比我们在苹果堆中挑苹果的时候,先在所有苹果里面挑出最好的一个,然后继续在剩余苹果里面再挑出最好的一个……如此类推。


怎么找到最好的苹果?那必须拿着某个苹果,对比一遍所有苹果,如果发现有更好的苹果,把好的苹果拿在手上,把次好的苹果放下,直至对比完所有的苹果后,手上拿着的就是最好的苹果


重复寻找法,就好比在苹果堆中不断挑最大最好看的苹果到自己的篮子里


为了方便讨论起见,我们设 n = 1亿


我们知道,求n个数最大值的比较次数为 n,求最大值的过程需要执行 10000 次,因此,重复寻找法的总比较次数为:


10000 × n


中场解答:


为什么这里只关注总比较次数?实际上我们在做排序的时候,比较次数与数据规模有明显关系,而其他的计算比如赋值、代码解析时间这些与数据规模无关,排序的关键是看比较次数。


为什么求最大值的比较次数为n呢?我们可以假想这样的情景:先拿出n个数中第一个数,作为临时最大值。在遍历n个数的过程中,如果发现有新的数字大于临时最大值,则以该数字为临时最大值。遍历完成以后,临时最大值即真正的最大值,比较的次数只需n次。


虽然这个问题有答案了,但是心里貌似有一些遗憾,不知道大家感受到了没?


其实,遍历10000次,这个次数有点多,为什么不可以遍历1次就得到结果呢?


方法二:局部淘汰法


实际上是可以的,还有一个能够一步到位的方法,叫做局部淘汰法


第1步:先创建一个数组,保存这1亿个数字中的前10000个数字,计算数组的最小数字。


第2步:遍历剩下的数字。如果遍历到某个数 A 大于数组的最小数字,那么则用 A 替换掉数组的最小数字。并重新计算数组的最小数字。

第3步:遍历完成后,数组内的数字即为所求。


以打麻将为例,一开始我们拿了n个牌,局部淘汰法类似我们在打麻将过程中,如果摸到一个自己手上最坏的牌要好的牌,就打出自己手上最坏的牌……如此类推,使得胜利的概率不断增大。


局部淘汰法,可以类比打麻将的过程,不断更换手上的牌,使得胜利的概率越来越大


这样,遍历1次就能得到最后的结果了。总比较次数如何呢?


最好的情况是,如果这1亿个数字刚好已经是降序排列,那么前10000个数字就是结果,只需要进行1次最小值的计算(比较次数 1 × 10000),9999万次最小值的比较(次数向上近似为 n)。


最坏的情况是,如果这1亿个数字刚好已经是升序排列,那么直到最后的10000个数字才是最终结果,因此需要进行9999万次最小值的计算(比较次数 n × 10000),9999万次最小值的比较(次数向上近似为 n 


因此,平均的情况是,要算5000万次最小值(比较次数为 1/2 × n × 10000),要算9999万次最小值比较(次数向上近似为 n ,因此总比较次数近似为 :


1/2 × n × 10000 = 5000 × n


总比较次数下降了一半,这个优化有点用。


但是……大家有没有觉得这个方法还有优化空间?


方法三:最小堆维护法


这个问题嘛……事实上是有的。这个方法能够大幅度降低总比较次数,称之为最小堆维护法


第1步:先利用前10000个数字,搭建一个元素个数为1万的最小堆


有模友可能会问,什么叫做最小堆呢?小智在这里解释一下:


首先,什么是堆?


关于堆这个概念,我们生活中的理解是东西堆在一起,比如沙堆、泥堆、还有小智的一堆东西


计时沙漏中的小沙堆


在计算机领域中,堆这个概念与生活中的有一点点类似,一般的堆也是上面窄下面宽的结构。堆结构,非常类似圆木堆放的结构,充满大自然的气息。


堆结构,可能源自圆木木堆的灵感


堆(heap)是一种基于(tree)的特殊的数据结构。堆有两种形式,分别是最大堆max heap)和最小堆min heap)。在堆顶的节点则被称为根节点。


我们关心最小堆就可以了。最小堆中,如果节点 A 是节点 B 的父节点,节点 A 中的键值必定小于或者等于节点 B 中的键值。根节点是堆的最小值。


以搬砖为例,我们要建一个金字塔,比较稳定的结构是下面重上面轻。最下面的我们放100kg的砖,然后上面可以放轻一点的砖。最小堆的结构也是类似的,位置越往上的节点键值越小。每一个节点都有一个键值,即所对应的数字,好比每一块砖头都对应一个重量,砖头的重量可以作为砖头的键值。


座结构稳定的小金字塔截面结构


堆的形式有非常多,不过堆的最常见实现形式是二叉堆binary heap),最小二叉堆一般也是被直接简称为最小堆,因此我们只需要理解二叉堆即可。我们可以画一个最小二叉堆的例子出来感受一下:


一个最小堆示例


对图中的最小堆分析,一共有三层圆圈,称之为节点,每一个上层的节点都连着下层的两个节点,而且上层节点的键值均比下层的两个节点的键值要小。这个就是最小堆的特征。


我们关注另外一个方面,图中8个元素的二叉堆里面,堆的高度是3。推而广之,对于一个有N个元素的二叉堆,其高度为 log2 N


这里还需要问大家一个问题:假设最小堆堆顶的键值改变,调整的时间是多少?


这个问题也就是问堆调整时间了。一般对于这种问题,我们都要算最坏情况。假设堆顶新键值大于堆里所有的数,那么堆顶这个元素需要调整到堆底,每一次调整都要下降一层,因此调整的次数为堆的高度,即 log2 N


建堆、堆调整以及堆排序的过程展示


解释得有点长,但是对于问题的理解是有帮助的哦。


我们来继续做题吧:


第2步:遍历剩下的数字,与最小堆的根元素键值进行对比。如果遍历到某个数确实大于根元素的键值,则替换根元素的键值,并进行堆调整


第3步:遍历完成后,最小堆当中的所有元素对应的数值即为所求。


刚刚说明了堆调整时间,最坏情况下调整时间为 log2 10000。同时要进行9999万次最小值比较(次数向上近似为 n)。因此上述步骤的比较次数最多为:


n × log2 10000 < 14 × n


总比较次数进一步下降了 5000 ÷ 14 > 350 倍,这个优化确实漂亮。


这个答案小智觉得算是满意的了。


上面这个题目属于 Top K 类问题,这类问题的解法,很多时候都可以用这种数据结构进行解答,往往能得到一些不错的结果。



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

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

相关文章

php webshell开源,[github开源]webshell连接器--Jeshell

前言&#xff1a;以前连接webshell都是用一个好朋友写的Webshellsniper&#xff0c;但是昨天使用webshellsniper测试的时候&#xff0c;发现不能支持shell_exec()这个php函数&#xff0c;问了一下才知道&#xff0c;他写的默认是只用eval()和assert()函数的webshell。于是&…

IT人的八大修炼神器

看到2018年的KPI&#xff0c;你是否感到崩溃&#xff1f;在这个充满竞争的时代&#xff0c;你需要用最有效的方式&#xff0c;学习最有用的知识&#xff0c;来提高自身技能。小编特意为大家准备IT人的八大修炼神器&#xff0c;推荐能帮助我们提升技术的公众号&#xff0c;欢迎大…

hotelling t2 matlab,pca主成份分析方法

1.应用pca的前提应用pca的前提是&#xff0c;连续信号具有相关性。相关性是什么&#xff0c;是冗余。就是要利用pca去除冗余。2.pca的定义pca是一种去除随机变量间相关性的线性变换。是一种常用的多元数据分析方法。pca将互相关的输入数据转换成统计上不相干的主成分(或者特征)…

如何在 WebAPI 中启用 CORS

浏览器安全策略上的安全限制可以有效的阻止 Ajax 向另外一个域server发起请求&#xff0c;这就是著名的 同源策略&#xff0c;那如何突破这种限制呢&#xff1f;可以使用 CORS &#xff08;Cross-Origin Resource Sharing&#xff09; 跨域资源共享来解决此类问题&#xff0c;它…

数据分析师+做过名企项目+懂运营+985毕业=跳槽失败?

数据已经成为很多企业的重要资源&#xff0c;数据分析已经成为了各行业的指导军事&#xff0c;但是数据分析师的工作从来都不是容易的。如今&#xff0c;数据分析师是一个互联网从业人士转型最快捷的入门职位&#xff0c;人工智能、大数据都要依附于数据分析。很多人也因为前途…

matlab 如何画二维图形,Matlab 学习 画图篇 一 二维图形

matlab给绘制二维图形提供了很多的函数&#xff0c;把一些绘制二维图形的基本函数做成一张表&#xff0c;如下图所示&#xff1a;我就按照表的顺序一一记录一些个函数的简略用法。首先是1.plot函数plot函数有很多重载方法&#xff0c;这里只做简单的介绍1.1 plot(Y)1.1 若Y是向…

Newbe.Claptrap 框架入门,第二步 —— 创建项目

接上一篇 《Newbe.Claptrap 框架入门&#xff0c;第一步 —— 开发环境准备》&#xff0c;我们继续了解如何创建一个 Newbe.Claptrap 项目。安装项目模板 打开控制台运行以下命令来安装最新的项目模板&#xff1a;dotnet new --install Newbe.Claptrap.Template安装完毕后&…

TTL expired in transit--问题篇~

今天在做东航事件处理时&#xff0c;发现远程登陆DMS服务器后&#xff0c;ping所有三层交换机<cisco 3550> 都发现一个现象:TTL expired in transit&#xff1b;如图1所示:之后用tracert -d IP 后&#xff0c;如图2所示:如图可见&#xff0c;可以清楚的发现&#xff0c…

【干货】机器学习中样本比例不平衡的处理方法

推荐阅读时间&#xff1a;5min~12min主要内容&#xff1a;机器学习中样本比例不平衡的处理方法在机器学习中&#xff0c;常常会遇到样本比例不平衡的问题&#xff0c;如对于一个二分类问题&#xff0c;正负样本的比例是 10:1。这种现象往往是由于本身数据来源决定的&#xff0c…

网易10万+课程迅速刷屏又迅速被封:“违规”背后的思考

从16号晚上8点前后上线到17号早上&#xff0c;不到16小时&#xff0c;网易云课堂的“年度运营大课”&#xff0c;已售出超10万份&#xff08;售价39元&#xff09;&#xff0c;可以说是非常现象级了。而取得如此现象级成果的背后&#xff0c;至少一个核心驱动力源自于一个“一级…

一起学习设计模式--03.工厂方法模式

简单工厂模式虽然简单&#xff0c;但是存在一个很严重的问题&#xff1a;由于静态工厂方法是根据传入的参数不同来创建不同的产品的&#xff0c;所以当系统中需要引入新产品时&#xff0c;就需要修改工厂类的源代码&#xff0c;这将违背开闭原则。为了实现增加新产品而不修改原…

求对一组数据进行排名的算法

为什么80%的码农都做不了架构师&#xff1f;>>> 我现在有一组数据&#xff0c;比如&#xff1a;25&#xff0c;19&#xff0c;29&#xff0c;3 怎么用java获得这组数据的排名&#xff0c;获得排名的结果应该是3&#xff0c;2&#xff0c;4&#xff0c;1 如果有相等…

一份数学小白也能读懂的「马尔可夫链蒙特卡洛方法」入门指南

在众多经典的贝叶斯方法中&#xff0c;马尔可夫链蒙特卡洛&#xff08;MCMC&#xff09;由于包含大量数学知识&#xff0c;且计算量很大&#xff0c;而显得格外特别。本文反其道而行之&#xff0c;试图通过通俗易懂且不包含数学语言的方法&#xff0c;帮助读者对 MCMC 有一个直…

使用 xunit 编写测试代码

使用 xunit 编写测试代码Introxunit 是 .NET 里使用非常广泛的一个测试框架&#xff0c;有很多测试项目都是在使用 xunit 作为测试框架&#xff0c;不仅仅有很多开源项目在使用&#xff0c;很多微软的项目也在使用 xunit 来作为测试框架。Get Started在 xunit 中不需要标记测试…

白话AI:看懂深度学习真的那么难吗?初中数学,就用10分钟

如果在这个人工智能的时代&#xff0c;作为一个有理想抱负的程序员&#xff0c;或者学生、爱好者&#xff0c;不懂深度学习这个超热的话题&#xff0c;似乎已经跟时代脱节了。但是&#xff0c;深度学习对数学的要求&#xff0c;包括微积分、线性代数和概率论与数理统计等&#…

IdentityServer4密码模式

Oatuth2协议的密码模式介绍用户会将用户名&#xff0c;密码给予客户端&#xff0c;但是客户端不保存此信息&#xff0c;客户端带着用户的密码请求认证服务器&#xff0c;认证服务器密码验证通过后后将token返回给客户端。 这里借用下阮一峰老师画的图&#xff08;博客地址》htt…

IKVM 编程武林之.NET派的北冥神功

为什么80%的码农都做不了架构师&#xff1f;>>> 在编程武林中&#xff0c;Java派成立较久底子雄厚&#xff0c;虽然掌门人Sun已经老态龙钟&#xff0c;镇山之技的Java语言已经被后进的新秀.NET派的C#压得喘不过气来&#xff0c;甚至有时候Sun老大还得跑到.NET派潜伏…

php 自定义菜单 openid,微信公众平台开发(99) 自定义菜单获取OpenID

关键字 微信公众平台 自定义菜单 OpenID作者&#xff1a;方倍工作室原文&#xff1a;http://www.cnblogs.com/txw1958/p/weixin-menu-get-openid.html在这篇微信公众平台开发教程中&#xff0c;我们将介绍如何在自定义菜单中获得用户的OpenID。本篇开发教程的实质是微信自定义菜…

mysql优化的重要参数 key_buffer_size table_cache

MySQL服务器端的参数有很多&#xff0c;但是对于大多数初学者来说&#xff0c;众多的参数往往使得我们不知所措&#xff0c;但是哪些参数是需要我们调整的&#xff0c;哪些对服务器的性能影响最大呢&#xff1f;对于使用Myisam存储引擎来说&#xff0c;主要有key_buffer_size和…

代码传奇 | 明明可以靠颜值 却用代码把人类送上了月球的女人——Margaret Hamilton

据说「软件工程师」这个名词就是她发明的玛格丽特站在阿波罗计算机指导手册 (AGC) 的源代码程序列表旁边&#xff0c;这些材料摞起来比她的人还要高。图片来源&#xff1a;Margaret Hamilton缔造传奇的人似乎有个共性&#xff1a;本来没想干一票大的&#xff0c;甚至她的打算都…