算法 (十六)哈希表:设计实现RandomPool结构、布隆过滤器和一致性哈希
1、设计实现RandomPool结构
【题目】 设计一种结构,在该结构中有如下三个功能:
- insert(key):将某个key加入到该结构,做到不重复加入。
- delete(key):将原本在结构中的某个key移除。
- getRandom(): 等概率随机返回结构中的任何一个key。
【要求】 Insert、delete和getRandom方法的时间复杂度都是 O(1)
分析:用两个哈希表,同时存取删除
代码实现如下:
package cn.nupt;
import java.util.HashMap;
/**
* @Description: RandomPool结构
*
* @author PizAn
* @Email [email protected]
* @date 2019年3月6日 上午9:49:20
*
*/
public class RandomPool {
private HashMap<String, Integer> keyToIndexMap; // 键为key,值为value
private HashMap<Integer, String> indexToKeyMap; // 键为value,值为key
private int index; // 这是记录的索引
public RandomPool() {
keyToIndexMap = new HashMap<String, Integer>();
indexToKeyMap = new HashMap<Integer, String>();
index = 0;
}
// 增加的方法,两个对应的map同时加
public void add(String key) {
if (!keyToIndexMap.containsKey(key)) {
keyToIndexMap.put(key, index);
indexToKeyMap.put(index, key);
index++; // 索引也要加
}
}
// 等概率随机返回结构中的任何一个key,关键是等概率,这里用到math.random * size,比如[0,1)*5 = [0,5),再取int
// 就等到[0,4]之间等概率的值,其中size就是我们放了多少个数,
public String getRandom() {
int size = keyToIndexMap.size(); // 获得map中键值对的个数
if (size == 0) {
return null;
}
return indexToKeyMap.get((int) (Math.random() * size));
}
// 删除一个键值对,这里需要注意的是需要保证index的连续性,不然会出现洞,解决方法就是用最后一个数填补这个洞,然后同步删除这个数
public void delete(String key) {
if (keyToIndexMap.containsKey(key)) {
int deleteIndex = keyToIndexMap.get(key); // 拿到这个要删除的key所对应的索引
int lastIndex = keyToIndexMap.size() - 1;
String lastKey = indexToKeyMap.get(lastIndex); // 拿到最后一个索引对应的key
keyToIndexMap.put(lastKey, deleteIndex); // 将keyToIndexMap里面的最后一个key所对应的索引换成我们即将要删除的key的索引,也就是说用最后一个数代替了我们要删除的数,不同的键可以对应相同的值
indexToKeyMap.put(deleteIndex, lastKey);// 将indexToKeyMap要删除的key的索引所对应的key换成做好一个索引所对应的key
keyToIndexMap.remove(key); // 最后两个map同步删除,
indexToKeyMap.remove(lastIndex);
index--;
}
}
}
2、布隆过滤器和一致性哈希
布隆过滤器是用来检索信息的,一致性哈希是用来负载均衡的,具体请看别的技术博客,讲的很好,下面自己写一些想法:
对于哈希函数来说,输入相同输出相同,输入不相同输出等分布(可能发生hash碰撞),输入可以无限制,输出有限制,通常在[0,264-1] 之间,一般在这个结果上取模m,使结果在[0,m]之间等分布
布隆过滤器有三个公式要记一下:
一致性哈希: