外部排序算法相关:主要用到归并排序,堆排序,桶排序,重点是先分成不同的块,然后从每个块中找到最小值写入磁盘,分析过程可以看看http://blog.csdn.net/jeason29/article/details/50474772

hash值算法

1.题目描述

给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?

2.思考过程

(1)首先我们最常想到的方法是读取文件a,建立哈希表(为什么要建立hash表?因为方便后面的查找),然后再读取文件b,遍历文件b中每个url,对于每个遍历,我们都执行查找hash表的操作,若hash表中搜索到了,则说明两文件共有,存入一个集合。

(2)但上述方法有一个明显问题,加载一个文件的数据需要50亿*64bytes = 320G远远大于4G内存,何况我们还需要分配哈希表数据结构所使用的空间,所以不可能一次性把文件中所有数据构建一个整体的hash表。

(3)针对上述问题,我们分治算法的思想。

step1:遍历文件a,对每个url求取hash(url)%1000,然后根据所取得的值将url分别存储到1000个小文件(记为a0,a1,...,a999,每个小文件约300M),为什么是1000?主要根据内存大小和要分治的文件大小来计算,我们就大致可以把320G大小分为1000份,每份大约300M(当然,到底能不能分布尽量均匀,得看hash函数的设计)

step2:遍历文件b,采取和a相同的方式将url分别存储到1000个小文件(记为b0,b1,...,b999)(为什么要这样做? 文件a的hash映射和文件b的hash映射函数要保持一致,这样的话相同的url就会保存在对应的小文件中,比如,如果a中有一个url记录data1被hash到了a99文件中,那么如果b中也有相同url,则一定被hash到了b99中)

所以现在问题转换成了:找出1000对小文件中每一对相同的url(不对应的小文件不可能有相同的url)

step3:因为每个hash大约300M,所以我们再可以采用(1)中的想法

http://blog.csdn.net/tiankong_/article/details/77234726

在所有具有性能优化的数据结构中,我想大家使用最多的就是hash表,是的,在具有定位查找上具有O(1)的常量时间,多么的简洁优美,

但是在特定的场合下:

①:对10亿个不重复的整数进行排序。

②:找出10亿个数字中重复的数字。

当然我只有普通的服务器,就算2G的内存吧,在这种场景下,我们该如何更好的挑选数据结构和算法呢?

问题分析

这年头,大牛们写的排序算法也就那么几个,首先我们算下放在内存中要多少G: (10亿 * 32)/(1024*1024*1024*8)=3.6G,可怜

的2G内存直接爆掉,所以各种神马的数据结构都玩不起来了,当然使用外排序还是可以解决问题的,由于要走IO所以暂时剔除,因为我们

要玩高性能,无望后我们想想可不可以在二进制位上做些手脚?

比如我要对{1,5,7,2}这四个byte类型的数字做排序,该怎么做呢?我们知道byte是占8个bit位,其实我们可以将数组中的值作为bit位的

key,value用”0,1“来标识该key是否出现过?下面看图:

从图中我们精彩的看到,我们的数组值都已经作为byte中的key了,最后我只要遍历对应的bit位是否为1就可以了,那么自然就成有序数组了。

可能有人说,我增加一个13怎么办?很简单,一个字节可以存放8个数,那我只要两个byte就可以解决问题了。

可以看出我将一个线性的数组变成了一个bit位的二维矩阵,最终我们需要的空间仅仅是:3.6G/32=0.1G即可,要注意的是bitmap排序不

是N的,而是取决于待排序数组中的最大值,在实际应用上关系也不大,比如我开10个线程去读byte数组,那么复杂度为:O(Max/10)。

(上面摘自http://www.cnblogs.com/huangxincheng/archive/2012/12/06/2804756.html,省去了代码部分,具体代码分析可见下文)

bitmap算法解释

一、bitmap算法思想

32位机器上,一个整形,比如int a; 在内存中占32bit位,可以用对应的32bit位对应十进制的0-31个数,bitmap算法利用这种思想处理大量数据的排序与查询.

优点:1.运算效率高,不许进行比较和移位;2.占用内存少,比如N=10000000;只需占用内存为N/8=1250000Byte=1.25M。 
   缺点:所有的数据不能重复。即不可对重复的数据进行排序和查找。

比如: 
          第一个4就是 
          00000000000000000000000000010000 
          而输入2的时候 
          00000000000000000000000000010100 
          输入3时候 
          00000000000000000000000000011100 
          输入1的时候 
          00000000000000000000000000011110

思想比较简单,关键是十进制和二进制bit位需要一个map图,把十进制的数映射到bit位。下面详细说明这个map映射表。

二、map映射表

假设需要排序或者查找的总数N=10000000,那么我们需要申请内存空间的大小为int a[1 + N/32],其中:a[0]在内存中占32为可以对应十进制数0-31,依次类推: 
bitmap表为:

a[0]--------->0-31 
a[1]--------->32-63 
a[2]--------->64-95 
a[3]--------->96-127 
..........

那么十进制数如何转换为对应的bit位,下面介绍用位移将十进制数转换为对应的bit位。

三、位移转换

例如十进制0,对应在a[0]所占的bit为中的第一位: 
00000000000000000000000000000001

0-31:对应在a[0]中

i =0                        00000000000000000000000000000000 
temp=0                  00000000000000000000000000000000 
answer=1                00000000000000000000000000000001 
i =1                         00000000000000000000000000000001 
temp=1                   00000000000000000000000000000001 
answer=2                 00000000000000000000000000000010 
i =2                          00000000000000000000000000000010 
temp=2                    00000000000000000000000000000010 
answer=4                  00000000000000000000000000000100 
i =30                         00000000000000000000000000011110 
temp=30                   00000000000000000000000000011110 
answer=1073741824  01000000000000000000000000000000 
i =31                         00000000000000000000000000011111 
temp=31                   00000000000000000000000000011111 
answer=-2147483648 10000000000000000000000000000000

32-63:对应在a[1]中

i =32                    00000000000000000000000000100000 
temp=0                00000000000000000000000000000000 
answer=1              00000000000000000000000000000001 
i =33                     00000000000000000000000000100001 
temp=1                 00000000000000000000000000000001 
answer=2               00000000000000000000000000000010 
i =34                      00000000000000000000000000100010 
temp=2                  00000000000000000000000000000010 
answer=4                00000000000000000000000000000100 
i =61                       00000000000000000000000000111101 
temp=29                  00000000000000000000000000011101 
answer=536870912   00100000000000000000000000000000 
i =62                        00000000000000000000000000111110 
temp=30                   00000000000000000000000000011110 
answer=1073741824  01000000000000000000000000000000 
i =63                         00000000000000000000000000111111 
temp=31                   00000000000000000000000000011111 
answer=-2147483648 10000000000000000000000000000000

浅析上面的对应表: 
1.求十进制0-N对应在数组a中的下标: 
十进制0-31,对应在a[0]中,先由十进制数n转换为与32的余可转化为对应在数组a中的下标。比如n=24,那么 n/32=0,则24对应在数组a中的下标为0。又比如n=60,那么n/32=1,则60对应在数组a中的下标为1,同理可以计算0-N在数组a中的下标。

2.求0-N对应0-31中的数: 
十进制0-31就对应0-31,而32-63则对应也是0-31,即给定一个数n可以通过模32求得对应0-31中的数。

3.利用移位0-31使得对应32bit位为1.

四、编程实现

解析本例中的void set(int i) {        a[i>>SHIFT] |=  (1<<(i & MASK)); }

1.i>>SHIFT: 
其中SHIFT=5,即i右移5为,2^5=32,相当于i/32,即求出十进制i对应在数组a中的下标。比如i=20,通过i>>SHIFT=20>>5=0 可求得i=20的下标为0;

2.i & MASK: 
其中MASK=0X1F,十六进制转化为十进制为31,二进制为0001 1111,i&(0001 1111)相当于保留i的后5位。

比如i=23,二进制为:0001 0111,那么 
                         0001 0111 
                   &    0001 1111 = 0001 0111 十进制为:23 
比如i=83,二进制为:0000 0000 0101 0011,那么 
                          0000 0000 0101 0011 
                     &   0000 0000 0001 0000 = 0000 0000 0001 0011 十进制为:19

i & MASK相当于i%32。

3.1<<(i & MASK) 
相当于把1左移 (i & MASK)位。 
比如(i & MASK)=20,那么i<<20就相当于: 
         0000 0000 0000 0000 0000 0000 0000 0001 >>20 
      =0000 0000 0000 1000 0000 0000 0000 0000

4.void set(int i) {        a[i>>SHIFT] |=  (1<<(i & MASK)); }等价于: 
void set(int i) 

   a[i/32] |= (1<<(i%32)); 
}

问题:

     一台主机,2G内存,40亿个不重复的没排过序的unsigned int的整数的文件,然后再给一个整数,如何快速判断这个整数是否在那40亿个数当中?
 

解决法案:

 

遍历法

     如果内存足够将40亿个数全部放到内存中,逐个遍历,此时时间复杂度为O(N).可是现在在内存不足,需要批量读一部分数据到内存然后在做判断,加上I/O操作的时间,时间复杂度远远大于O(N).
     这时,性能问题主要集中在I/O操作,和遍历数组上。那么有没有降低时间复杂度的方法呢?答案是肯定的,如果我们假定内存是足够的,只去优化时间,可以得到下面的方法。
 

直接寻址表法

    申请一个4G超大数组char a[0~2*32-1],将文件中出现的数字置为1,没有出现的置为0.
例如文件存在一个整数1000022,就将a[1000022]=1.

a 0 1 2 ...... 1000022 ..... 100000030 ... 2*32- 1 
flag 0 1 1 1 0 0 1 0 1
    这时时间复杂度为O(1),可是空间问题还没有解决。分析下我们的算法,以所需判断的整数为数组下标,用0/1来区分整数是否在。一共用了一个字节来作为标记位,而事实上1-bit就足够标记了。如果能把这部分空间优化掉,4G/8 < 2G 那么就可以解决问题了。看下面的方法。
 

Bit-Map

    将整数映射到bit上,例如整数10,10/8=1,10%8=2,那么就将a[1]的b[2]置为1。这样时间复杂度即是O(1),内存也得到了压缩。
a 0 1 ...... 2*32 / 8- 1 
bit 0 1 2 3 4 5 6 7  0 1 2 3 4 5 6 7  ...... 0 1 2 3 4 5 6 7 
flag 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 ...... 0 0 0 0 0 0 0 0
 
 

BitMap 应用

枚举

1.全组合

字符串全组合枚举(对于长度为n的字符串,组合方式有2^n种),如:abcdef,可以构造一个从字符串到二进制的映射关系,通过枚举二进制来进行全排序。

null --> 000000

f --> 000001

e -->  000010

ef --> 000011

……

abcedf --> 111111

2.哈米尔顿距离

给定N(1<=N<=100000)个五维的点A(x1,x2,x3,x4,x5),求两个点X(x1,x2,x3,x4,x5)和Y(y1,y2,y3,y4,y5),使得他们的哈密顿距离(d=|x1-y1| + |x2-y2| + |x3-y3| + |x4-y4| + |x5-y5|)最大。

搜索

爬虫系统中常用的URL去重(Bloom Filter算法)

压缩

在2.5亿个整数中找出不重复的整数,注,内存不足以容纳这2.5亿个整数?

给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中?

位排序

(以上摘抄自http://blog.csdn.net/qq_26891045/article/details/51137589)

另:可以看看KMP(字符串匹配算法)

大数据排序算法:外部排序,bitmap算法;大数据去重算法:hash算法,bitmap算法的更多相关文章

  1. BitMap算法知识笔记以及在大数据方向的使用

    概述 所谓的BitMap算法就是位图算法,简单说就是用一个bit位来标记某个元素所对应的value,而key即是该元素,由于BitMap使用了bit位来存储数据,因此可以大大节省存储空间,这是很常用的 ...

  2. 十大经典排序算法+sort排序

    本文转自:十大经典排序算法,其中有动图+代码详解,本文简单介绍+个人理解. 排序算法 经典的算法问题,也是面试过程中经常被问到的问题.排序算法简单分类如下: 这些排序算法的时间复杂度等参数如下: 其中 ...

  3. 数据结构中常用的排序算法 && 时间复杂度 && 空间复杂度

    第一部分:数据结构中常用的排序算法 数据结构中的排序算法一般包括冒泡排序.选择排序.插入排序.归并排序和 快速排序, 当然还有很多其他的排序方式,这里主要介绍这五种排序方式. 排序是数据结构中的主要内 ...

  4. 使用 js 实现十大排序算法: 桶排序

    使用 js 实现十大排序算法: 桶排序 桶排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  5. 使用 js 实现十大排序算法: 计数排序

    使用 js 实现十大排序算法: 计数排序 计数排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  6. 使用 js 实现十大排序算法: 希尔排序

    使用 js 实现十大排序算法: 希尔排序 希尔排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  7. 使用 js 实现十大排序算法: 选择排序

    使用 js 实现十大排序算法: 选择排序 选择排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  8. 利用BitMap进行大数据排序去重

    1.问题 问题提出: M(如10亿)个int整数,只有其中N个数重复出现过,读取到内存中并将重复的整数删除. 2.解决方案 问题分析: 我们肯定会先想到在计算机内存中开辟M个int整型数据数组,来on ...

  9. Java数据结构和算法 - 高级排序

    希尔排序 Q: 什么是希尔排序? A: 希尔排序因计算机科学家Donald L.Shell而得名,他在1959年发现了希尔排序算法. A: 希尔排序基于插入排序,但是增加了一个新的特性,大大地提高了插 ...

随机推荐

  1. COGS 1507. [IOI2000]邮局

    1507. [IOI2000]邮局 ★☆   输入文件:postoffice.in   输出文件:postoffice.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] ...

  2. 【BZOJ1007】[HNOI2008]水平可见直线 半平面交

    [BZOJ1007][HNOI2008]水平可见直线 Description 在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见 ...

  3. Black And White(DFS+剪枝)

    Black And White Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 512000/512000 K (Java/Others ...

  4. WebApi 中使用 Token

    1.登陆的时候根据用户信息生成Token var token = FormsAuthentication.Encrypt( new FormsAuthenticationTicket( , " ...

  5. UITableView 右侧索引

    1.设置右侧索引字体颜色 self.tabView.sectionIndexColor = [UIColor blackColor]; 2.设置右侧索引背景色 self.cityTabView.sec ...

  6. greenlet和gevent模块的区别?

    协程是一中多任务实现方式,它不需要多个进程或线程就可以实现多任务. yield能实现协程,不过实现过程不易于理解,greenlet是在这方面做了改进,通过switch. greenlet可以实现协程, ...

  7. You can also run `php --ini` inside terminal to see which files are used by PHP in CLI mode.

    [root@localhost dreamstart]# composer installLoading composer repositories with package informationI ...

  8. C#读取excel 找不到可安装的ISAM

    实在没有办法了 就仔细的查看了 一下数据链接字符串: string strConn = "Provider=Microsoft.Jet.Oledb.4.0;Data Source=" ...

  9. Advanced GET 9.1 修正汉化版(免注册、页面加载、保存都正常)

    http://www.55188.com/viewthread.php?tid=2846679 Advanced GET 9.1 修正汉化版(免注册.页面加载.保存都正常) 网上流传的很多GET9.1 ...

  10. windows下SecureCRT无法使用backspace(空格键)和上下左右键

    在使用SecureCRT登陆liunx(我的为CenterOS)系统,发现删除(backspace)键.和上下左右键不起作用,郁闷了很久没有找到解决办法, 今天终于看到了一篇有用的文章,在此记录一下! ...