哈希函数的重要特征
1.输入为无限的值 输入为有限集合
2.相同的输入会有相同的输出
3.不同的输入也可能会出现不同的输出(哈希碰撞 概率极低)
4.获得的值是离散且平均的 就是说 在固定区域类获得的hash返回结果是平均的
加入我们返回值是在1-100之间,那么输入10000个数 得到的结果 为1 或者其他的数量都基本相同,几乎是10个。
一道题:给我们40亿个数,想要求出出现次数最多的值,要求规定内存是1G,我们会对这个40亿个数求哈希值,然后%100,得到的结果就是在0,99之间,而且离散均匀分布 就是说 每个值上分布的个数几乎一致,然后求出每个里面个数最多的,然后最后凑出100个再进行比较 得出最多的:
哈希表:
- 设计RandomPool,有如下功能,insert,delete,getRandom,其中的getRandom可以等概率的获取数。要求所有操作时间复杂度为O(1);
只有删除操作稍微麻烦一点,需要我们将最后一位填报上删除掉的位置即可。
public class RandomPool{
public static void main(String[] args){
Pool<String> pool=new Pool();
pool.insert("g");
pool.insert("s");
pool.insert("x");
System.out.println(pool.getRandom());
}
private static class Pool<T>{
private HashMap<T,Integer> map1=new HashMap();//里面装的是字符串 和它对应的索引
private HashMap<Integer,T> map2=new HashMap();//里面装的是索引 和它对应的字符串
private int size=0;
public T getRandom(){//随机返回一个
if(size==0){
return null;
}
int index=(int)(Math.random() * size);//随机获取的索引值
return map2.get(index);
}
public void insert(T key){
map1.put(key, size);
map2.put(size++, key);
}
public void delete(T key){
if(map1.containsKey(key)){
int index1=map1.get(key);
map1.put(map2.get(size-1), index1);
map1.remove(key);
map2.put(index1, map2.get(size-1));
map2.remove(--size);
}
}
}
}
- 布隆过滤器,我们在了解这个之前先看一看位图:
//位图
public class BitMap {
int arr[]=new int[10];//10个int类型的数组就是 32字节 * 10 = 320bit 320位 可以代表320个状态信息
//获取某一位的信息 比如170位
public int getNum(int num){
int index=num/32;//首先是数组的第几个位置
int n=num%32;//然后是那个位置的第几个字节
return (arr[index]>>n) & 1;//将这个数据右移n位 让该位的数跑到字的最右边的位置 和 1取& 得到当前位是1 还是0
}
//将某一位的信息修改为1
public void changeToOne(int num){
int index=num/32;
int n=num%32;
arr[index]=arr[index]|(1<<n);//将我们1左移到 该位上 然后取或操作 将这个位置上的值修改为1
}
public void changeToZero(int num){
int index=num/32;
int n=num%32;
arr[index]= arr[index]& ~(1<<n);//将我们的1左移到该位置上 然后取反 其他位置全为1 该位置为0 两个取&操作 会将该位置转换为0
}
}
我们的布隆过滤器是干什么的,主要是用于网站黑名单的过滤,一个浏览器有很多url的黑名单,上亿种,如果我们用字符串来存储的话,会耗费几百个G的内存,但如果放在外存里面又很耗时。此时我们就用位图来标记:
1.首先创建一个长度为m位的数组(1字节=8位)
2.然后我们拿到这个网站的url,对它做k种不同的Hash操作,做完后将他进行对m的取余运算,得到的值,在数组种对应位置标记为1,每次操作得到的结果都将对应位置标记为1.
3.当我们想要判断一个url是否是黑名单中的,直接进行k中不同的Hash操作,然后对m进行取余运算,得到的值在数组中寻找是否所有的位置都为1,如果都为1那么它就是黑名单中的url。
这样操作就是我们的布隆过滤器的操作,这样的操作更加节省空间,但是会有失误。
一共存在两种失误:1.将白名单中的url误判为黑名单中的url 2.将黑名单中的url误判为白名单的url
我们的布隆过滤器只会存在第一种失误 因为可能会存在某一个url进行k中hash计算后对m取模结果和黑名单中的一致(哈希碰撞),导致判断失误。
但是这种失误是可以通过我们的设计来减少的,合理的设计m的大小,和k种操作的大小能够减少失误。m应该稍微大一点,k也应该大一点,这样能够减少不同url出现相同值的可能性,但是k不能太大,太大会导致我们的m会很轻易的被填满,然后造成更多的失误。
布隆过滤器的数值的计算公式: