外部排序算法相关:主要用到归并排序,堆排序,桶排序,重点是先分红不一样的块,而后从每一个块中找到最小值写入磁盘,分析过程能够看看http://blog.csdn.net/jeason29/article/details/50474772html
hash值算法算法
给定a、b两个文件,各存放50亿个url,每一个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?编程
(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算法解释
1、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映射表。
2、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位。
3、位移转换
例如十进制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.
4、编程实现
解析本例中的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));
}
a | 0 | 1 | 2 | ...... | 1000022 | ..... | 100000030 | ... | 2*32- 1 |
flag | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 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 |
字符串全组合枚举(对于长度为n的字符串,组合方式有2^n种),如:abcdef,能够构造一个从字符串到二进制的映射关系,经过枚举二进制来进行全排序。
null --> 000000
f --> 000001
e --> 000010
ef --> 000011
……
abcedf --> 111111
给定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(字符串匹配算法)