??xml version="1.0" encoding="utf-8" standalone="yes"?> 在数据结构的评上,我们学习了不的排序法Q冒泡,堆,快排Q归q等。但是这些排序方法有着共同的特点,那就是所有的操作都是在内存中完成的,法q程中不需要IOQ这׃得这L法M上速度比较快,但是也随之出C一个问题:当需要排序的数据量异常的大的时候,以上的算法就昑־力不从心了。这时候,你需要一U另外的排序法Q它的名字叫“外排?#8221;?/p> 通常的,讑֤的内存读取速度要比外存d速度快得多(RAM的访问速度大约是磁盘的25万倍)Q但是内存的定w却要比外存小很多Q当所有的数据不能在内存中完全放下的时候,需要用到外排序。这是外排序的一个显著特征?/p> 外排序其实是采用一U分治(Divide and conquer algorithmQ的法设计思想Q将一个大问题划分成相对独立的若干个小问题Q解军_问题Q得到小问题的答案,然后合ƈ问题的{案Q最l得到原始大问题的答案?/p> 在这里,我们举一个外排的典型例子Q二路外部归q排序,假设我们有一个大文gQ里面是待排序的数据Q一共N个,q些数据在内存中放不下。排序过E如下: 以上是二\外部归ƈ排序的基本思\Q毫无疑问,q种排序法需要读取外存(IOQ次Cؓlog(2,N/m)Q这时候算法的性能瓉已经不在内存中排序的旉复杂度上Q而是内外村交换数据IO的次C。这里我补充一句,各种操作的性能差别Q?/p> d|络 > 盘文gIO > d数据?> 内存d q个可谓是程序性能的黄金法则,各位在写Ҏ能要求比较高的E序时一定要考虑?/p> 好,a归正传,二\归ƈ排序q个法的性能时比较低的。因此就有了多\归ƈ排序法Q其IO的次Cؓlog(b, N/m)Q其中b为几路归q。这个可以参考以下地址Q?/p> http://zh.wikipedia.org/wiki/%E5%A4%96%E6%8E%92%E5%BA%8F 淘宝不同用户的浏览log有上千万or亿数据(有重复)Q统计其中有相同览爱好的用戗?/p> 转蝲h明出处:http://diducoder.com/mass-data-topic-9-external-sort.html 在信息大爆炸的今天,有了搜烦引擎的帮助,使得我们能够快速,便捷的找到所求。提到搜索引擎,׃得不说VSM模型Q说到VSMQ就不得不聊倒排索引。可以毫不夸张的Ԍ倒排索引是搜索引擎的基石?/p> VSM全称是Vector Space Model(向量I间模型)Q是IR(Information Retrieval信息?模型中的一U,׃其简单,直观Q高效,所以被q泛的应用到搜烦引擎的架构中?8q的Google是凭借这L一个模型,开始了它的疯狂扩张之\。废话不多说Q让我们来看看到底VSM是一个什么东东?/p> 在开始之前,我默认大家对U性代数里面的向量(Vector)有一定了解的。向量是既有大小又有方向的量Q通常用有向线D表C,向量有:加、减、倍数、内U、距R模、夹角的q算?/p> 文档(Document)Q一个完整的信息单元Q对应的搜烦引擎pȝ里,是指一个个的网c?/p> 标引?Term)Q文档的基本构成单位Q例如在英文中可以看做是一个单词,在中文中可以看作一个词语?/p> 查询(Query)Q一个用L输入Q一般由多个Term构成?/p> 那么用一句话概况搜烦引擎所做的事情是Q对于用戯入的QueryQ找到最怼的Documentq回l用戗而这正是IR模型所解决的问题: 信息索模型是指如何对查询和文档进行表C,然后对它们进行相似度计算的框架和Ҏ?/p> 举个单的例子Q?/p> 现在有两文?Document)分别?“春风来了Q春天的脚步q了” ?“春风不度玉门?#8221;。然后输入的Query?#8220;春风”Q从直观上感觉,前者和输入的查询更相关一些,因ؓ它包含有2个春Q但q只是我们的直观感觉Q如何量化呢Q要知道计算机是门严谨的学科^_^。这个时候,我们前面讲的Term和VSM模型派上用Z?/p> 首先我们要确定向量的l数Q这时候就需要一个字典库Q字典库的大,x向量的维数。在该例中,字典?span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 12px; font-style: inherit; font-family: Consolas, Monaco, 'Courier New', Courier, monospace; outline-width: 0px; outline-style: initial; outline-color: initial; vertical-align: baseline; line-height: 18px; white-space: pre; ">{春风,来了,春天, ?脚步,q了,不度,玉门关} 【引a?/h1>
【什么是外排序?/h1>
【实战训l?/h1>
]]>引言Q?/h1>
VSM索模?/h1>
PS:Z单v见,q里分词的粒度很大?/p>
Query和Document都量化ؓ向量以后Q那么就可以计算用户的查询和哪个文档怼性更大了。简单的计算l果是D1和D2同Query的内U都?Q囧。当然了Q如果分词粒度再l一些,查询的结果就是另外一个样子了Q因此分词的_度也是会对查询l果Q主要是召回率和准确率)造成影响的?/p>
上述的例子是用一个很单的例子来说明VSM模型的,计算文档怼度的时候也是采用最原始的内U的ҎQƈ且只考虑了词?TF)影响因子Q而没有考虑反词?IDF)Q而现在比较常用的是cos夹角法,影响因子也非常多Q据传Google的媄响因子有100+之多?br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />大名鼎鼎的Lucene目是采用VSM模型构徏的,VSM的核心公式如下(由cos夹角法演变,此处省去推导q程Q?/p>
从上面的例子不难看出Q如果向量的l度(Ҏ语来,q个g般在30w-45w)变大Q而且文档数量(通常都是量?变多Q那么计一ơ相x,开销是非常大的,如何解决q个问题呢?不要忘记了,我们q节的主题就?倒排索引Q主角终于粉墨登ZQ!Q?/p>
倒排索引非常cM我们前面提到的Hashl构。以下内Ҏ自维基百U:
倒排索引Q英语:Inverted indexQ,也常被称?strong style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-style: inherit; outline-width: 0px; outline-style: initial; outline-color: initial; vertical-align: baseline; ">反向索引?strong style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-style: inherit; outline-width: 0px; outline-style: initial; outline-color: initial; vertical-align: baseline; ">|入档案?strong style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-style: inherit; outline-width: 0px; outline-style: initial; outline-color: initial; vertical-align: baseline; ">反向档案Q是一U?a title="索引" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; color: #1982d1; text-decoration: none; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-style: inherit; outline-width: 0px; outline-style: initial; outline-color: initial; vertical-align: baseline; ">索引ҎQ被用来存储?a title="全文搜烦" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; color: #1982d1; text-decoration: none; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-style: inherit; outline-width: 0px; outline-style: initial; outline-color: initial; vertical-align: baseline; ">全文搜烦下某个单词在一个文档或者一l文档中?a title="存储位置" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; color: #1982d1; text-decoration: none; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-style: inherit; outline-width: 0px; outline-style: initial; outline-color: initial; vertical-align: baseline; ">存储位置?a title="映射" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; color: #1982d1; text-decoration: none; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-style: inherit; outline-width: 0px; outline-style: initial; outline-color: initial; vertical-align: baseline; ">映射。它?a title="文档索系l? style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; color: #1982d1; text-decoration: none; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-style: inherit; outline-width: 0px; outline-style: initial; outline-color: initial; vertical-align: baseline; ">文档索系l?/a>中最常用?a title="数据l构" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; color: #1982d1; text-decoration: none; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-style: inherit; outline-width: 0px; outline-style: initial; outline-color: initial; vertical-align: baseline; ">数据l构?/p>
有两U不同的反向索引形式Q?/p>
- 一条记录的水^反向索引Q或者反向档案烦引)包含每个引用单词的文档的列表?/li>
- 一个单词的水^反向索引Q或者完全反向烦引)又包含每个单词在一个文档中的位|?/li>
׃面的定义可以知道Q一个倒排索引包含一个字典的索引和所有词的列表。其中字典烦引中包含了所有的Term(通俗理解为文档中的词)Q烦引后面跟的列表则保存该词的信?出现的文档号Q甚臛_含在每个文档中的位置信息)。下面我们还采用上面的方法D一个简单的例子来说明倒排索引?/p>
例如现在我们要对三篇文档建立索引(实际应用中,文档的数量是量?Q?/p>
文档1(D1)Q中国移动互联网发展q?/p>
文档2(D2)Q移动互联网未来的潜力巨?/p>
文档3(D3)Q中华民族是个勤劳的民族
那么文档中的词典集合为:{中国Q移动,互联|,发展Q迅速,未来Q的Q潜力,巨大Q中华,民族Q是Q个Q勤劳}
建好的烦引如下图Q?/p>
在上面的索引中,存储了两个信息,文档号和出现的次数。徏立好索引以后Q我们就可以开始查询了。例如现在有一个Query?#8221;中国Ud”。首先分词得到Term集合{中国Q移动}Q查倒排索引Q分别计query和d1,d2,d3的距R有没有发现Q倒排表徏立好以后Q就不需要在索整个文档库Q而是直接从字兔R合中扑ֈ“中国”?#8220;Ud”Q然后遍历后面的列表直接计算?/p>
对倒排索引l构我们已经有了初步的了解,但在实际应用中还有些需要解决的问题(主要是由量数据引v?。笔者列举一些问题,q给出相应的解决ҎQ抛砖以引玉Q希望大家可以展开讨论Q?/p>
1.左侧的烦引表如何建立?怎么做才能最高效Q?/p>
可能有h不假思烦回答Q左侧的索引当然要采取hashl构啊,q样可以快速的定位到字兔R。但是这样问题又来了Qhash函数如何选取呢?而且hash是有撞的,但是倒排表似乎又是不允许撞的存在的。事实上Q虽然倒排表和hash异常的相思,但是两者还是有很大区别的,其实在这里我们可以采用前面提到的Bitmap的思想Q每个Term(单词)对应一个位|?当然了,q里不是一个比特位)Q而且是一一对应的。如何能够做到呢Q一般在文字处理中,有很多的~码Q汉字中的GBK~码基本上就可以包含所有用到的汉字Q每个汉字的GBK~码是确定的Q因此一个Term?#8221;ID”也就定了,从而可以做到快速定位。注Q得C个汉字的GBKh非常快的q程Q可以理解ؓO(1)的时间复杂度?/p>
2.如何快速的d删除更新索引Q?/p>
有经验的码农都知道,一般在pȝ?#8220;做加?#8221;的代h“做减?#8221;的代仯低很多,在搜索引擎中中也不例外。因此,在倒排表中Q遇到要删除一个文档,其实不是真正的删除,而是其标记删除。这样一个减法操作的代h比较小了?/p>
3.那么多的量文档Q如果存储呢Q有么有什么备份策略呢Q?/p>
当然了,一台机器是存储不下的,分布式存储是采取的。一般的备䆾保存3份就_了?/p>
好了Q倒排索引l于完工了,不的地方请指正。谢?/p>
做h要厚道,转蝲h明出处:http://diducoder.com/mass-data-topic-8-inverted-index.html
索引是对数据库表中一列或多列的D行排序的一U结构,使用索引可快速访问数据库表中的特定信息?/p>
数据库烦引好比是一本书前面的目录,能加快数据库的查询速度?/p>
例如q样一个查询:select * from table1 where id=44。如果没有烦引,必须遍历整个表,直到ID{于44的这一行被扑ֈ为止Q有了烦引之?必须是在IDq一列上建立的烦?Q直接在索引里面?4Q也是在IDq一列找Q,可以得知这一行的位置Q也是扑ֈ了这一行。可见,索引是用来定位的?/p>
索引分ؓ聚簇索引和非聚簇索引两种Q聚烦?是按照数据存攄物理位置为顺序的Q而非聚簇索引׃一样了Q聚烦引能提高多行索的速度Q而非聚簇索引对于单行的检索很快?/p>
建立索引的目的是加快对表中记录的查找或排序?/p>
讄索引要付ZLQ一是增加了数据库的存储I间Q二是在插入和修Ҏ据时要花费较多的旉(因ؓ索引也要随之变动)?/p>
创徏索引可以大大提高pȝ的性能?/p>
W一Q通过创徏唯一性烦引,可以保证数据库表中每一行数据的唯一性?br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />W二Q可以大大加快数据的索速度Q这也是创徏索引的最主要的原因?br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />W三Q可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义?br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />W四Q在使用分组和排序子句进行数据检索时Q同样可以显著减查询中分组和排序的旉?br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />W五Q通过使用索引Q可以在查询的过E中Q用优化隐藏器Q提高系l的性能?/p>
也许会有问:增加索引有如此多的优点,Z么不对表中的每一个列创徏一个烦引呢Q因为,增加索引也有许多不利的方面?/p>
W一Q创建烦引和l护索引要耗费旉Q这U时间随着数据量的增加而增加?br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />W二Q烦引需要占物理I间Q除了数据表占数据空间之外,每一个烦引还要占一定的物理I间Q如果要建立聚簇索引Q那么需要的I间׃更大?br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />W三Q当对表中的数据q行增加、删除和修改的时候,索引也要动态的l护Q这样就降低了数据的l护速度?/p>
索引是徏立在数据库表中的某些列的上面。在创徏索引的时候,应该考虑在哪些列上可以创建烦引,在哪些列上不能创建烦引。一般来_应该在这些列上创建烦引:
在经帔R要搜索的列上Q可以加快搜索的速度Q?br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />在作Z键的列上Q强制该列的唯一性和l织表中数据的排列结构;
在经常用在连接的列上Q这些列主要是一些外键,可以加快q接的速度Q在l常需要根据范围进行搜索的列上创徏索引Q因为烦引已l排序,其指定的范围是连l的Q?br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />在经帔R要排序的列上创徏索引Q因为烦引已l排序,q样查询可以利用索引的排序,加快排序查询旉Q?br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />在经怋用在WHERE子句中的列上面创建烦引,加快条g的判断速度?/p>
同样Q对于有些列不应该创建烦引。一般来_不应该创建烦引的的这些列h下列特点Q?/p>
W一Q对于那些在查询中很用或者参考的列不应该创徏索引。这是因为,既然q些列很用到Q因此有索引或者无索引Qƈ不能提高查询速度。相反,׃增加了烦引,反而降低了pȝ的维护速度和增大了I间需求?/p>
W二Q对于那些只有很数据值的列也不应该增加烦引。这是因为,׃q些列的取值很,例如Z表的性别列,在查询的l果中,l果集的数据行占了表中数据行的很大比例,即需要在表中搜烦的数据行的比例很大。增加烦引,q不能明昑֊快检索速度?/p>
W三Q对于那些定义ؓtext, image和bit数据cd的列不应该增加烦引。这是因为,q些列的数据量要么相当大Q要么取值很?不利于用烦引?/p>
W四Q当修改性能q远大于索性能Ӟ不应该创建烦引。这是因为,修改性能和检索性能是互相矛盄。当增加索引Ӟ会提高检索性能Q但是会降低修改性能。当减少索引Ӟ会提高修Ҏ能Q降低检索性能。因此,当修Ҏ作远q多于检索操作时Q不应该创徏索引?/p>
此外Q除了数据库索引之外Q在LAMPl果如此行的今天,数据库(其是MySQLQ性能优化也是量数据处理的一个热炏V下面就l合自己的经验,聊一聊MySQL数据库优化的几个斚w?/p>
首先Q在数据库设计的时候,要能够充分的利用索引带来的性能提升Q至于如何徏立烦引,建立什么样的烦引,在哪些字D上建立索引Q上面已l讲的很清楚了,q里不在赘述。另外就是设计数据库的原则就是尽可能的q行数据库写操作Q插入,更新Q删除等Q,查询简单越好。如下:
其次Q配|缓存是必不可少的,配置~存可以有效的降低数据库查询dơ数Q从而缓解数据库服务器压力,辑ֈ优化的目的,一定程度上来讲Q这是一?#8220;围魏救n”的办法。可配置的缓存包括烦引缓?key_buffer)Q排序缓?sort_buffer)Q查询缓?query_buffer)Q表描述W缓?table_cache)Q如下图Q?/p>
W三Q切表,切表也是一U比较流行的数据库优化方法。分表包括两U方式:横向分表和纵向分表,其中Q横向分表比较有使用意义Q故名思议Q横向切表就是指把记录分C同的表中Q而每条记录仍旧是完整的(U向切表后每条记录是不完整的Q,例如原始表中?00条记录,我要切成2个表Q那么最单也是最常用的方法就是ID取摸切表法,本例中,把ID?,3,5,7。。。的记录存在一个表中,ID?,4,6,8,。。。的记录存在另一张表中。虽然横向切表可以减查询强度,但是它也破坏了原始表的完整性,如果该表的统计操作比较多Q那么就不适合横向切表。横向切表有个非常典型的用法Q就是用h据:每个用户的用h据一般都比较庞大Q但是每个用h据之间的关系不大Q因此这里很适合横向切表。最后,要记住一句话是Q分表会造成查询的负担,因此在数据库设计之初Q要惛_是否真的适合切表的优化:
W四Q日志分析,在数据库q行了较长一D|间以后,会积累大量的LOG日志Q其实这里面的蕴늚有用的信息量q是很大的。通过分析日志Q可以找到系l性能的瓶颈,从而进一步寻找优化方案?/p>
以上讲的都是单机MySQL的性能优化的一些经验,但是随着信息大爆炸,单机的数据库服务器已l不能满x们的需求,于是Q多多节点,分布式数据库|络出现了,其一般的l构如下Q?/p>
q种分布式集的技术关键就?#8220;同步复制”。。。《未完待l。。。?/p>
做h要厚道,转蝲h明出处:http://diducoder.com/mass-data-topic-7-index-and-
【什么是双层桶?br />事实上,与其说双层桶划分是一U数据结构,不如说它是一U算法设计思想。面对一堆大量的数据我们无法处理的时候,我们可以其分成一个个的单元Q然后根据一定的{略来处理这些小单元Q从而达到目的?/p>
【适用范围?br />Wk大,中位敎ͼ不重复或重复的数?/p>
【基本原理及要点?br />因ؓ元素范围很大Q不能利用直接寻址表,所以通过多次划分Q逐步定范围Q然后最后在一个可以接受的范围内进行。可以通过多次~小Q双层只是一个例子,分治才是其根本(只是“只分不治”Q?/p>
【扩展?br />当有时候需要用一个小范围的数据来构造一个大数据Q也是可以利用这U思想Q相比之下不同的Q只是其中的逆过E?/p>
【问题实例?br />1).2.5亿个整数中找Z重复的整数的个数Q内存空间不以容纳q?.5亿个整数?/span>
有点像鸽巢原理,整数个数?^32,也就是,我们可以这2^32个数Q划分ؓ2^8个区?比如用单个文件代表一个区?Q然后将数据分离C同的区域Q然后不同的区域在利用bitmap可以直接解决了。也是说只要有_的磁盘空_可以很方便的解冟?当然q个题也可以用我们前面讲q的BitMapҎ解决Q正所谓条条大道通罗马~~~
2).5亿个int扑֮们的中位数?/strong>
q个例子比上面那个更明显。首先我们将int划分?^16个区域,然后d数据l计落到各个区域里的数的个数Q之后我们根据统计结果就可以判断中位数落到那个区域,同时知道q个区域中的W几大数刚好是中位数。然后第二次扫描我们只统计落在这个区域中的那些数可以了?/p>
实际上,如果不是int是int64Q我们可以经q?ơ这L划分卛_降低到可以接受的E度。即可以先将int64分成2^24个区域,然后定区域的第?大数Q在该区域分成2^20个子区域Q然后确定是子区域的W几大数Q然后子区域里的数的个数只有2^20Q就可以直接利用direct addr tableq行l计了?/p>
3).现在有一?-30000的随机数生成器。请Ҏq个随机数生成器Q设计一个抽奖范围是0-350000彩票中奖L列表Q其中要包含20000个中奖号码?/span>
q个题刚好和上面两个思想相反Q一??万的随机数生成器要生成一??5万的随机数。那么我们完全可以将0-35万的区间分成35/3=12个区_然后每个区间的长度都于{于3万,q样我们可以用题目l的随机数生成器来生成了Q然后再加上该区间的基数。那么要每个区间生成多少个随机数呢?计算公式是Q区间长?随机数密度,在本题目中就?0000*Q?0000/350000Q。最后要注意一点,该题目是有隐含条件的Q彩,q意味着你生成的随机数里面不能有重复Q这也是我ؓ什么用双层桶划分思想的另外一个原因?/p>
做h好厚道,转蝲h明出处:http://diducoder.com/mass-data-topic-6-multi-dividing.html
【什么是堆?/strong>
概念Q堆是一U特D的二叉树,具备以下两种性质
1Q每个节点的值都大于Q或者都于Q称为最堆Q其子节点的?br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />2Q树是完全^衡的Qƈ且最后一层的树叶都在最左边
q样定义了一个最大堆。如下图用一个数l来表示堆:
那么下面介绍二叉堆:二叉堆是一U完全二叉树Q其L子树的左双点(如果有的话)的键g定比根节点大Q上囑օ实就是一个二叉堆?/p>
你一定发觉了Q最的一个元素就是数l第一个元素,那么二叉堆这U有序队列如何入队呢Q看图:
假设要在q个二叉堆里入队一个单元,键gؓ2Q那只需在数l末֊入这个元素,然后可能把q个元素往上挪Q直到挪不动Q经q了q种复杂度ؓΟ(logn)的操作,二叉堆还是二叉堆?/p>
那如何出队呢Q也不难Q看图:
出队一定是出数l的W一个元素,q么来第一个元素以前的位置成了空位,我们需要把q个IZ挪至叶子节点Q然后把数组最后一个元素插入这个空位,把这?#8220;IZ”量往上挪。这U操作的复杂度也?#927;(logn)?/p>
【适用范围?/strong>
量数据前n大,q且n比较,堆可以放入内?/span>
【基本原理及要点?/strong>
最大堆求前n,最堆求前n大。方法,比如求前n,我们比较当前元素与最大堆里的最大元素,如果它小于最大元素,则应该替换那个最大元 素。这h后得到的n个元素就是最的n个。适合大数据量Q求前n,n的大比较小的情况,q样可以扫描一遍即可得到所有的前n元素Q效率很高?/span>
【扩展?/strong>
双堆Q一个最大堆与一个最堆l合Q可以用来维护中位数?/span>
【问题实例?/strong>
1)100w个数中找最大的?00个数?br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />用一?00个元素大的最堆卛_?/span>
做h要厚道:转蝲h明出处:http://diducoder.com/mass-data-topic-5-heap.html
【什么是Bit-map?/strong>
所谓的Bit-map是用一个bit位来标记某个元素对应的ValueQ?而Keyx该元素。由于采用了Bit为单位来存储数据Q因此在存储I间斚wQ可以大大节省?/p>
如果说了q么多还没明白什么是Bit-mapQ那么我们来看一个具体的例子Q假设我们要?-7内的5个元?4,7,2,5,3)排序Q这里假设这些元素没有重复)。那么我们就可以采用Bit-map的方法来辑ֈ排序的目的。要表示8个数Q我们就只需?个BitQ?BytesQ,首先我们开?Byte的空_这些空间的所有Bit位都|ؓ0(如下图:)
然后遍历q?个元素,首先W一个元素是4Q那么就?对应的位|ؓ1Q可以这h?p+(i/8)|(0×01<<(i%8)) 当然了这里的操作涉及到Big-ending和Little-ending的情况,q里默认为Big-endingQ?因ؓ是从零开始的Q所以要把第五位|ؓ一Q如下图Q:
然后再处理第二个元素7Q将W八位置?,Q接着再处理第三个元素Q一直到最后处理完所有的元素Q将相应的位|ؓ1Q这时候的内存的Bit位的状态如下:
然后我们现在遍历一遍Bit区域Q将该位是一的位的编可出(2Q?Q?Q?Q?Q,q样pC排序的目的。下面的代码l出了一个BitMap的用法:排序?/p>
//定义每个Byte中有8个Bit?#include Qmemory.hQ?#define BYTESIZE 8 void SetBit(char *p, int posi) { for(int i=0; i Q?(posi/BYTESIZE); i++) { p++; } *p = *p|(0x01Q<(posi%BYTESIZE));//该Bit位赋? return; } void BitMapSortDemo() { //Z单v见,我们不考虑负数 int num[] = {3,5,2,10,6,12,8,14,9}; //BufferLenq个值是Ҏ待排序的数据中最大值确定的 //待排序中的最大值是14Q因此只需?个Bytes(16个Bit) //可以了? const int BufferLen = 2; char *pBuffer = new char[BufferLen]; //要将所有的Bit位置?Q否则结果不可预知? memset(pBuffer,0,BufferLen); for(int i=0;iQ?;i++) { //首先相应Bit位上|ؓ1 SetBit(pBuffer,num[i]); } //输出排序l果 for(int i=0;iQBufferLen;i++)//每次处理一个字?Byte) { for(int j=0;jQBYTESIZE;j++)//处理该字节中的每个Bit? { //判断该位上是否是1Q进行输出,q里的判断比较笨? //首先得到该第j位的掩码Q?x01Q<jQ,内存区中的 //位和此掩码作与操作。最后判断掩码是否和处理后的 //l果相同 if((*pBuffer&(0x01Q<j)) == (0x01Q<j)) { printf("%d ",i*BYTESIZE + j); } } pBuffer++; } } int _tmain(int argc, _TCHAR* argv[]) { BitMapSortDemo(); return 0; }
【适用范围?/strong>
可进行数据的快速查找,判重Q删除,一般来说数据范围是int?0倍以?/p>
【基本原理及要点?/strong>
使用bit数组来表C某些元素是否存在,比如8位电话号?/p>
【扩展?/strong>
Bloom filter可以看做是对bit-map的扩?/p>
【问题实例?/strong>
1)已知某个文g内包含一些电话号码,每个L?位数字,l计不同L的个数?/strong>
8位最?9 999 999Q大概需?9m个bitQ大?0几m字节的内存即可?Q可以理解ؓ?-99 999 999的数字,每个数字对应一个Bit位,所以只需?9M个Bit==12.4MBytesQ这Pq了小的12.4M左右的内存表CZ所有的8位数的电话)
2)2.5亿个整数中找Z重复的整数的个数Q内存空间不以容纳q?.5亿个整数?/strong>
bit-map扩展一下,?bit表示一个数卛_Q?表示未出玎ͼ1表示出现一ơ,2表示出现2ơ及以上Q在遍历q些数的时候,如果对应位置的值是0Q则其|ؓ1Q如果是1Q将其置?Q如果是2Q则保持不变。或者我们不?bit来进行表C,我们用两个bit-map卛_模拟实现q个2bit-mapQ都是一L道理?/p>
做h好厚道,转蝲h明出处:http://diducoder.com/mass-data-4-bitmap.html
【什么是Hash?/span>
HashQ一般翻译做“散列”Q也有直接音译ؓ“哈希”的,是把Q意长度的输入Q又叫做预映, pre-imageQ,通过散列法Q变换成固定长度的输出,该输出就是散列倹{这U{换是一U压~映,也就是,散列值的I间通常q小于输入的I间Q不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入倹{简单的说就是一U将L长度的消息压~到某一固定长度?a style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; color: #1982d1; text-decoration: none; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-style: inherit; outline-width: 0px; outline-style: initial; outline-color: initial; vertical-align: baseline; ">消息摘要的函数?/p>
HASH主要用于信息安全领域中加密算法,它把一些不同长度的信息转化成杂q128位的~码,q些~码值叫做HASH? 也可以说Qhash是扑ֈ一U数据内容和数据存放地址之间的映关pR?/p>
数组的特ҎQ寻址ҎQ插入和删除困难Q而链表的特点是:d困难Q插入和删除Ҏ。那么我们能不能l合两者的Ҏ,做出一U寻址ҎQ插入删除也Ҏ的数据结构?{案是肯定的Q这是我们要提L哈希表,哈希表有多种不同的实现方法,我接下来解释的是最常用的一U方?#8212;—拉链法,我们可以理解?#8220;链表的数l?#8221;Q如图:
左边很明显是个数l,数组的每个成员包括一个指针,指向一个链表的_当然q个链表可能为空Q也可能元素很多。我们根据元素的一些特征把元素分配C同的链表中去Q也是根据这些特征,扑ֈ正确的链表,再从链表中找个元素?/p>
元素特征转变为数l下标的Ҏ是散列法。散列法当然不止一U,下面列出三种比较常用的?/p>
1Q除法散列法
最直观的一U,上图使用的就是这U散列法Q公式:
index = value % 16
学过汇编的都知道Q求模数其实是通过一个除法运得到的Q所以叫“除法散列?#8221;?/p>
2Q^Ҏ列法
求index是非帔RJ的操作Q而乘法的q算要比除法来得省时Q对现在的CPU来说Q估计我们感觉不出来Q,所以我们考虑把除法换成乘法和一个位UL作。公式:
index = (value * value) >> 28
如果数值分配比较均匀的话q种Ҏ能得C错的l果Q但我上面画的那个图的各个元素的值算出来的index都是0——非常p|。也怽q有个问题,value如果很大Qvalue * value不会溢出吗?{案是会的,但我们这个乘法不兛_溢出Q因为我们根本不是ؓ了获取相乘结果,而是Z获取index?/p>
3Q斐波那契(FibonacciQ散列法
qx散列法的~点是显而易见的Q所以我们能不能扑և一个理想的乘数Q而不是拿value本n当作乘数呢?{案是肯定的?/p>
1Q对?6位整数而言Q这个乘数是40503
2Q对?2位整数而言Q这个乘数是2654435769
3Q对?4位整数而言Q这个乘数是11400714819323198485
q几?#8220;理想乘数”是如何得出来的呢Q这跟一个法则有养I叫黄金分割法则,而描q黄金分割法则的最l典表达式无疑就是著名的斐L那契数列Q如果你q有兴趣Q就到网上查找一?#8220;斐L那契数列”{关键字Q我数学水^有限Q不知道怎么描述清楚Z么,另外斐L那契数列的值居然和太阳pd大行星的轨道半径的比例出奇吻合,很神奇,对么Q?/p>
Ҏ们常见的32位整数而言Q公式:
i ndex = (value * 2654435769) >> 28
如果用这U斐波那契散列法的话Q那我上面的囑ְ变成q样了:
很明显,用斐波那契散列法调整之后要比原来的取摸散列法好很多?/p>
【适用范围?/span>
快速查找,删除的基本数据结构,通常需要L据量可以攑օ内存?/p>
【基本原理及要点?/strong>
hash函数选择Q针对字W串Q整敎ͼ排列Q具体相应的hashҎ?br style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; " />撞处理Q一U是open hashingQ也UCؓ拉链法;另一U就是closed hashingQ也U开地址法,opened addressing?/p>
【扩展?/strong>
d-left hashing中的d是多个的意思,我们先简化这个问题,看一?-left hashing?-left hashing指的是将一个哈希表分成长度相等的两半,分别叫做T1和T2Q给T1和T2分别配备一个哈希函敎ͼh1和h2。在存储一个新的keyӞ?时用两个哈希函数q行计算Q得Z个地址h1[key]和h2[key]。这旉要检查T1中的h1[key]位置和T2中的h2[key]位置Q哪一?位置已经存储的(有碰撞的Qkey比较多,然后新key存储在负载少的位|。如果两边一样多Q比如两个位|都为空或者都存储了一个keyQ就把新key 存储在左边的T1子表中,2-left也由此而来。在查找一个keyӞ必须q行两次hashQ同时查找两个位|?/p>
【问题实例?/strong>
1).量日志数据Q提取出某日讉K癑ֺơ数最多的那个IP?/p>
IP的数目还是有限的Q最?^32个,所以可以考虑使用haship直接存入内存Q然后进行统计?/p>
做h要厚道,转蝲h明出处: http://diducoder.com/mass-data-topic-3-hash.html
Bloom Filter是一U空间效率很高的随机数据l构Q它利用位数l很z地表示一个集合,q能判断一个元素是否属于这个集合。Bloom Filter的这U高效是有一定代LQ在判断一个元素是否属于某个集合时Q有可能会把不属于这个集合的元素误认为属于这个集合(false positiveQ。因此,Bloom Filter不适合那些“雉?#8221;的应用场合。而在能容忍低错误率的应用场合下,采用Bloom Filter的数据结构,可以通过极少的错误换取了存储I间的极大节省?nbsp;q里有一关?a style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; color: #1982d1; text-decoration: none; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-style: inherit; outline-width: 0px; outline-style: initial; outline-color: initial; vertical-align: baseline; ">Bloom Filter的详l介l,不太懂的博友可以看看?/span>
可以用来实现数据字典Q进行数据的判重Q或者集合求交集
在这些解x案之上,再借助一定的例子来剖析v量数据处理问题的解决Ҏ?/span>
其实在园子里面好多类似的面试题都可以用这LҎ来解{,比如癑ֺ的TopK热门查询问题Q某日IP最多访问问题?/span>
把这c问题研I好了,面试像百度,腾讯q样的公司就完全没问题了Q!Q?/span>