大数据处理算法文档格式.docx
《大数据处理算法文档格式.docx》由会员分享,可在线阅读,更多相关《大数据处理算法文档格式.docx(15页珍藏版)》请在冰豆网上搜索。
12.this.tem=newbyte[length];
13.}
14.
15.publicvoidadd(intnum){
16.if(num<
tem.length){
17.if(tem[num]!
=1){
18.tem[num]=1;
19.}
20.}
21.}
22.
23.publicbooleancontain(intnum){
24.if(num<
25.if(tem[num]==1){
26.returntrue;
27.}
28.}
29.returnfalse;
30.}
31.
32.publicstaticvoidmain(String[]args){
33./*运行前内存*/
34.longbeforeMemory=Runtime.getRuntime().totalMemory();
35.longstart1=System.currentTimeMillis();
36.BitSetset=newBitSet(2000000000);
37.for(inti=0;
i<
2000000000;
i++){
38./*假设898989这个数不在20亿个数里面*/
39.if(i!
=898989){
40.set.set(i,true);
41.}
42.}
43./*创建20亿个数后所占内存*/
44.longafterMemory=Runtime.getRuntime().totalMemory();
45.longend1=System.currentTimeMillis();
46.System.out.println("
总共内存使用:
"
+(afterMemory-beforeMemory)/1024/1024+"
MB"
);
47.System.out.println("
存入内存耗时:
+(end1-start1)+"
毫秒"
48.longstart2=System.currentTimeMillis();
49.booleanisExit1=set.get(898989);
50.booleanisExit2=set.get(900000);
51.
52.longend2=System.currentTimeMillis();
53./*输出在20亿个数中判断898989是否包含在里面*/
54.System.out.println(isExit1);
55.System.out.println("
20个亿中"
+(isExit1?
包含"
:
不包含"
)+898989);
56.System.out.println("
+(isExit2?
)+900000);
57.System.out.println("
查询用时:
+(end2-start2)+"
58.}
59.
60.}
BloomFilter算法
XX面试题:
给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?
BloomFilter是由Bloom在1970年提出的一种多哈希函数映射的快速查找算法。
通常应用在一些需要快速判断某个元素是否属于集合,但是并不严格要求100%正确的场合。
一.实例
为了说明BloomFilter存在的重要意义,举一个实例:
(实例一),假设要你写一个网络蜘蛛(webcrawler)。
由于网络间的链接错综复杂,蜘蛛在网络间爬行很可能会形成“环”。
为了避免形成“环”,就需要知道蜘蛛已经访问过那些URL。
给一个URL,怎样知道蜘蛛是否已经访问过呢?
稍微想想,
(实例二)给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?
就会有如下几种方案:
1.将访问过的URL保存到数据库。
2.用HashSet将访问过的URL保存起来。
那只需接近O
(1)的代价就可以查到一个URL是否被访问过了。
3.URL经过MD5或SHA-1等单向哈希后再保存到HashSet或数据库。
4.Bit-Map方法。
建立一个BitSet,将每个URL经过一个哈希函数映射到某一位。
方法1~3都是将访问过的URL完整保存,方法4则只标记URL的一个映射位。
以上方法在数据量较小的情况下都能完美解决问题,但是当数据量变得非常庞大时问题就来了。
方法1的缺点:
数据量变得非常庞大后关系型数据库查询的效率会变得很低。
而且每来一个URL就启动一次数据库查询是不是太小题大做了?
方法2的缺点:
太消耗内存。
随着URL的增多,占用的内存会越来越多。
就算只有1亿个URL,每个URL只算50个字符,就需要5GB内存。
方法3:
由于字符串经过MD5处理后的信息摘要长度只有128Bit,SHA-1处理后也只有160Bit,因此方法3比方法2节省了好几倍的内存。
方法4消耗内存是相对较少的,但缺点是单一哈希函数发生冲突的概率太高。
还记得数据结构课上学过的Hash表冲突的各种解决方法么?
若要降低冲突发生的概率到1%,就要将BitSet的长度设置为URL个数的100倍。
实质上上面的算法都忽略了一个重要的隐含条件:
允许小概率的出错,不一定要100%准确!
也就是说少量url实际上没有没网络蜘蛛访问,而将它们错判为已访问的代价是很小的——大不了少抓几个网页呗。
例如有一组字符arr:
”哈哈“,”呵呵“........
字符串:
“哈哈”
哈希算法1处理后:
8
哈希算法2处理后:
1
3
插入BitArray后
再处理字符串:
“呵呵”
2
9
继续插入BitArray后,如果继续游字符串,继续以这种方式插入
判断”在这些字符串是否包含”嘻嘻“
7
只要判断下标分别为0,1,7位置的值是否都为1,如下图因为位置0跟位置7的值不为1
所以”嘻嘻“不包含在arr中,反之如果都为1怎包含
java代码实现如下
1.importjava.util.ArrayList;
2.importjava.util.BitSet;
3.importjava.util.List;
4.
5./**
6.*BloomFilter算法
7.*
8.*@authorJYC506
9.*
10.*/
11.publicclassBloomFilter{
12./*哈希函数*/
13.privateList<
IHashFunction>
hashFuctionList;
14./*构造方法*/
15.publicBloomFilter(){
16.this.hashFuctionList=newArrayList<
();
17.}
18./*添加哈希函数类*/
19.publicvoidaddHashFunction(IHashFunctionhashFunction){
20.this.hashFuctionList.add(hashFunction);
22./*删除hash函数*/
23.publicvoidremoveHashFunction(IHashFunctionhashFunction){
24.this.hashFuctionList.remove(hashFunction);
25.}
26./*判断是否被包含*/
27.publicbooleancontain(BitSetbitSet,Stringstr){
28.for(IHashFunctionhash:
hashFuctionList){
29.inthashCode=hash.toHashCode(str);
30.if(hashCode<
0){
31.hashCode=-hashCode;
32.}
33.if(bitSet.get(hashCode)==false){
34.returnfalse;
35.}
36.}
37.returntrue;
38.}
39./*添加到bitSet*/
40.publicvoidtoBitSet(BitSetbitSet,Stringstr){
41.for(IHashFunctionhash:
42.inthashCode=hash.toHashCode(str);
43.if(hashCode<
44.hashCode=-hashCode;
45.}
46.bitSet.set(hashCode,true);
47.}
48.}
49.
50.publicstaticvoidmain(String[]args){
51.BloomFilterbloomFilter=newBloomFilter();
52./*添加3个哈希函数*/
53.bloomFilter.addHashFunction(newJavaHash());
54.bloomFilter.addHashFunction(newRSHash());
55.bloomFilter.addHashFunction(newSDBMHash());
56./*长度为2的24次方*/
57.BitSetbitSet=newBitSet(1<
<
25);
58./*判断test1很test2重复的字符串*/
59.String[]test1=newString[]{"
哈哈"
"
我"
大家"
逗比"
有钱人性"
小米"
Iphone"
helloWorld"
};
60.for(Stringstr1:
test1){
61.bloomFilter.toBitSet(bitSet,str1);
62.}
63.String[]test2=newString[]{"
我的"
有钱的人性"
Iphone6s"
64.for(Stringstr2:
test2){
65.if(bloomFilter.contain(bitSet,str2)){
66.System.out.println("
'
+str2+"
是重复的"
67.}
68.}
69.
70.}
71.}
72./*哈希函数接口*/
73.interfaceIHashFunction{
74.inttoHashCode(Stringstr);
75.}
76.
77.classJavaHashimplementsIHashFunction{
78.
79.@Override
80.publicinttoHashCode(Stringstr){
81.returnstr.hashCode();
82.}
83.
84.}
85.
86.classRSHashimplementsIHashFunction{
87.
88.@Override
89.publicinttoHashCode(Stringstr){
90.intb=378551;
91.inta=63689;
92.inthash=0;
93.for(inti=0;
str.length();
94.hash=hash*a+str.charAt(i);
95.a=a*b;
96.}
97.returnhash;
98.}
99.
100.}
101.
102.classSDBMHashimplementsIHashFunction{
103.
104.@Override
105.publicinttoHashCode(Stringstr){
106.inthash=0;
107.for(inti=0;
i++)
108.hash=str.charAt(i)+(hash<
6)+(hash<
16)-hash;
109.returnhash;
110.}
111.
112.}
分而治之/hash映射+hash统计+堆/快速/归并排序
XX面试题1、海量日志数据,提取出某日访问XX次数最多的那个IP。
IP是32位的,最多有个2^32个IP。
同样可以采用映射的方法,比如模1000,把整个大文件映射为1000个小文件,再找出每个小文中出现频率最大的IP(可以采用hash_map进行频率统计,然后再找出频率最大的几个)及相应的频率。
然后再在这1000个最大的IP中,找出那个频率最大的IP,即为所求。
XX面试题2、搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。
假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果除去重复后,不超过3百万个。
一个查询串的重复度越高,说明查询它的用户越多,也就是越热门。
),请你统计最热门的10个查询串,要求使用的内存不能超过1G。
第一步借用hash统计进行预处理:
先对这批海量数据预处理(维护一个Key为Query字串,Value为该Query出现次数,即Hashmap(Query,Value),每次读取一个Query,如果该字串不在Table中,那么加入该字串,并且将Value值设为1;
如果该字串在Table中,那么将该字串的计数加一即可。
最终我们在O(N)(N为1千万,因为要遍历整个数组一遍才能统计处每个query出现的次数)的时间复杂度内用Hash表完成了统计;
第二步借用堆排序找出最热门的10个查询串:
时间复杂度为N'
*logK。
维护一个K(该题目中是10)大小的小根堆,然后遍历3百万个Query,分别和根元素进行对比(对比value的值),找出10个value值最大的query
最终的时间复杂度是:
O(N)+N'
*O(logK),(N为1000万,N’为300万)
或者:
采用trie树,关键字域存该查询串出现的次数,没有出现为0。
最后用10个元素的最小推来对出现频率进行排序。
我们先看HashMap实现
1.HashMap的数据结构
数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端。
数组
数组存储区间是连续的,占用内存严重,故空间复杂的很大。
但数组的二分查找时间复杂度小,为O
(1);
数组的特点是:
寻址容易,插入和删除困难;
链表
链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N)。
链表的特点是:
寻址困难,插入和删除容易。
哈希表
那么我们能不能综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构?
答案是肯定的,这就是我们要提起的哈希表。
哈希表((Hashtable)既满足了数据的查找方便,同时不占用太多的内容空间,使用也十分方便。
哈希表有多种不同的实现方法,我接下来解释的是最常用的一种方法——拉链法,我们可以理解为“链表的数组”
我用java自己实现了一个HashMap,当然这比较简点,不过能说明大概原理,改有的功能基本上有了
index=hashCode(key)=key%16
哈希算法很多,下面我用了java自带的,当然你也可以用别的
1./**
2.*自定义HashMap
3.*@authorJYC506
4.*
5.*@param<
K>
6.*@param<
V>
7.*/
8.publicclassHashMap<
K,V>
{
9.
10.privatestaticfinalintCAPACTITY=16;
11.
12.transientEntry<
[]table=null;
13.
14.@SuppressWarnings("
unchecked"
)
15.publicHashMap(){
16.super();
17.table=newEntry[CAPACTITY];
18.}
19.
20./*哈希算法*/
21.privatefinalinttoHashCode(Objectobj){
22.inth=0;
23.if(objinstanceofString){
24.returnStringHash.toHashCode((String)obj);
26.h^=obj.hashCode();
27.h^=(h>
>
20)^(h>
12);
28.returnh^(h>
7)^(h>
4);
29.}
30./*放入hashMap*/
31.publicvoidput(Kkey,Vvalue){
32.inthashCode=this.toHashCode(key);
33.intindex=hashCode%CAPACTITY;
34.if(table[index]==null){
35.table[index]=newEntry<
(key,value,hashCode);
36.}else{
37.for(Entry<
entry=table[index];
entry!
=null;
entry=entry.nextEntry){
38.if(entry.hashCode==hashCode&
&
(entry.key==key||key.equals(entry.key))){
39.entry.value=value;
40.return;
43.Entry<
entry2=table[index];
44.Entry<
entry3=newEntry<
45.entry3.nextEntry=entry2;
46.table[index]=entry3;
47.
49.}
50./*获取值*/
51.publicVget(Kkey){
52.inthashCode=this.toHashCode(key);
53.intindex=hashCode%CAPACTITY;
54.if(table[index]==null){
55.returnnull;
56.}else{
57.for(Entry<
58.if(entry.hashCode==hashCode&
59.returnentry.value;
61.}
62.returnnull;
63.
64.}
65.}
66./*删除*/
67.publicvoidremove(Kkey){
68.inthashCode=this