布隆过滤
基本原理:当一个元素被加入集合时,通过k个散列函数将这个元素映射到一个位数组中的k个点,把他们置为1。检索时,我们只需要看这些点是不是都是1,就(大约)直到集合中有没有他了:如果这些点中有任何一个点为0,则被检索元素一定不存在;如果都是1,则该元素很可能存在。
原理图:
分析:
不用保存原始数据,只需要保存原始数据的位图,位图占据的空间很小。只需要经过k次hash进行比对即,效率高。但是会不准确,造成一定的误差
模拟代码如下:
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
public class BoolmFilter {
public static final int NUM_SLOTS=1024*1024*8; //位图的长度
public static final int NUM_HASH=8; //hash函数的个数 每一个hash函数结果用于标记一个位
private BigInteger bitMap=new BigInteger("0"); //位图
public static void main(String[] args) {
BoolmFilter bf=new BoolmFilter();
List<String> list=new ArrayList<String>();
list.add("eyufgvdvc");
list.add("eyufgvdvc1");
list.add("eyufgvdvc2");
list.add("eyufgvdvc3");
list.add("eyufgvdvc4");
list.add("eyufgvdvc5");
for (int i = 0; i <list.size() ; i++) {
bf.addElement(list.get(i));
}
System.out.println(bf.checkElement("eyufgvdvc"));
System.out.println(bf.checkElement("eyufgvdvc1"));
System.out.println(bf.checkElement("eyufgvdvc2"));
System.out.println(bf.checkElement("eyufgvdv"));
System.out.println(bf.checkElement("eyufgvd"));
System.out.println(bf.checkElement("eyufgvdvcc"));
}
//模拟的hash算法
public int hash(String message,int n){
message=message+String.valueOf(n);
try {
MessageDigest md5=MessageDigest.getInstance("md5"); //MD5是将任意输入映射成128位整数的hash函数
byte[] bytes=message.getBytes(); //字符串转化成字节数组
md5.update(bytes);
byte[] digest = md5.digest(); //128位 16个字节的数组
BigInteger bigInteger=new BigInteger(digest); //至此 获取到了message的128位整数
return Math.abs(bigInteger.intValue())%NUM_SLOTS; //128位整数可能超出位图的大小 所以进行了取余操作
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
Logger.getLogger(BoolmFilter.class.getName()).log(Level.SEVERE,null,e);
}
return -1;
}
//处理原始数据:每hash(message)一次---->就标注一个位;操作k次
//hash的值域位:0~NUM_SLOTS-1
public void addElement(String meaasge){
for (int i = 0; i <NUM_HASH ; i++) {
int hashCode=hash(meaasge,i); //进行k次hash操作 根据参数的不同 此处模拟了8个不同的hash函数
if(!bitMap.testBit(hashCode)){ //如果该位置还不为1
bitMap=bitMa***ew BigInteger("1").shiftLeft(hashCode)); //用于标注位图的该位值为: 1
}
}
}
//判断某一个元素是否存在
public boolean checkElement(String message){
for (int i = 0; i <NUM_HASH ; i++) {
int hashCode=hash(message,i); //hashCode代表一个位置
if(!bitMap.testBit(hashCode)){ //如果在位图的该位置为0
return false;
}
}
return true; //不精确,有可能误判
}
}