自己实现一个简单的布谷鸟散列
2017-08-03 14:38
543 查看
需求
自己实现一个简单的布谷鸟散列(Cuckoo hashtable)。分析
布谷鸟哈希最早于2001 年由Rasmus Pagh 和Flemming Friche Rodler 提出 。该哈希方法是为了解决哈希冲突的问题而提出,利用较少计算换取了较大空间。名称源于该哈希方法行为类似于布谷鸟在别的鸟巢中下蛋,并将别的鸟蛋挤出的行为。它具有占用空间小、查询迅速等特性,可用于Bloom filter 和内存管理 。算法描述
算法使用多个不同哈希函数计算对应key 的位置。当多个哈希任意位置为空,则选择一个位置插入
当多个哈希有位置为空时,则插入到空位置
当多个哈希位置均不为空时,随机选择两者之一的位置上key 踢出,计算踢出的key 另一个哈希值对应的位置进行插入,转至2执行(即当再次插入位置为空时插入,仍旧不为空时,再踢出这个key)
接口
interface HashTable<E> { int size(); boolean isEmpty(); void clear(); boolean contains(E e); void add(E e); boolean remove(E e); } interface HashFamily<E> { int getNumOfFunctions(); void generateNewFunctions(); int hash(E e, int which); }
实现类
class CuckooHashTable<E> implements HashTable<E> { private static final float LOAD_FACTOR = 0.4f; private static final int ALLOWED_REHASHES = 1; private static final int DEFAULT_TABLE_SIZE = 101; private final HashFamily<? super E> hashFunctions; private final int numHashFunctions; private Object[] array; private int currentSize; public CuckooHashTable(HashFamily<? super E> hashFunctions) { this(hashFunctions, DEFAULT_TABLE_SIZE); } public CuckooHashTable(HashFamily<? super E> hashFunctions, int size) { allocateArray(nextPrime(size)); currentSize = 0; this.hashFunctions = hashFunctions; numHashFunctions = hashFunctions.getNumOfFunctions(); } private void allocateArray(int arraySize) { array = new Object[arraySize]; } private void doClear() { currentSize = 0; for (int i = 0; i < array.length; i++) array[i] = null; } @Override public int size() { return currentSize; } @Override public boolean isEmpty() { return currentSize == 0; } @Override public void clear() { doClear(); } @Override public boolean contains(E e) { return findPos(e) != -1; } @Override public void add(E e) { if (contains(e)) return; if (currentSize >= array.length * LOAD_FACTOR) expand(); addHelper(e); } private int rehashes = 0; private Random r = new Random(); private void addHelper(E e) { final int COUNT_LIMIT = 100; while (true) { int lastPos = -1; int pos; for (int count = 0; count < COUNT_LIMIT; count++) { for (int i = 0; i < numHashFunctions; i++) { pos = hash(e, i); if (array[pos] == null) { array[pos] = e; currentSize++; return; } } int i = 0; do { pos = hash(e, r.nextInt(numHashFunctions)); } while (pos == lastPos && i++ < 5); E tmp = array(lastPos = pos); array[pos] = e; e = tmp; } if (++rehashes > ALLOWED_REHASHES) { expand(); rehashes = 0; } else rehash(); } } private void expand() { rehash((int) (array.length / LOAD_FACTOR)); } private void rehash() { hashFunctions.generateNewFunctions(); rehash(array.length); } private void rehash(int newLength) { @SuppressWarnings("unchecked") E[] oldArray = (E[]) array; allocateArray(nextPrime(newLength)); currentSize = 0; for (E e : oldArray) { if (e != null) add(e); } } @SuppressWarnings("unchecked") private E array(int index) { return (E) array[index]; } @Override public boolean remove(E e) { int pos = findPos(e); if (pos != -1) { array[pos] = null; currentSize--; } return pos != -1; } private int findPos(E e) { for (int i = 0; i < numHashFunctions; i++) { int pos = hash(e, i); if (array[pos] != null && array[pos].equals(e)) return pos; } return -1; } private int hash(E e, int which) { int hashVal = hashFunctions.hash(e, which); hashVal %= array.length; if (hashVal < 0) hashVal += array.length; return hashVal; } @Override public String toString() { StringJoiner joiner = new StringJoiner(); for (int i = 0; i < array.length; i++) { if (array[i] != null) joiner.add(array[i]); } return joiner.toString(); } private int nextPrime(int n) { if (n % 2 == 0) n++; while (!isPrime(n)) n += 2; return n; } private boolean isPrime(int n) { if (n == 2 || n == 3) return true; if (n == 1 || n % 2 == 0) return false; for (int i = 3; i * i <= n; i += 2) if (n % i == 0) return false; return true; } } class StringHashFamily implements HashFamily<String> { private final int[] MUTLIPLIERS; private final Random r = new Random(); public StringHashFamily(int size) { MUTLIPLIERS = new int[size]; generateNewFunctions(); } @Override public int getNumOfFunctions() { return MUTLIPLIERS.length; } @Override public void generateNewFunctions() { for (int i = 0; i < MUTLIPLIERS.length; i++) MUTLIPLIERS[i] = r.nextInt(); } @Override public int hash(String e, int which) { final int mutliplier = MUTLIPLIERS[which]; int hashVal = 0; for (int i = 0; i < e.length(); i++) hashVal = mutliplier * hashVal + e.charAt(i); return hashVal; } }
相关文章推荐
- 【NROS-00】自己实现一个简单操作系统
- 自己编写的一个java简单的窗口实现两点求园面积
- 自己动手实现一个简单的 IOC
- 自己动手系列——实现一个简单的LinkedList
- 自己实现的一个简单的HttpEngine库
- 自己用 Netty 实现一个简单的 RPC
- 新手自己搭建、开发网络直播平台历程——了解实现一个简单直播平台的结构
- C++自己实现一个简单地Vector
- 使用hadoop命令rcc生成Record 一个简单的方法来实现自己的定义writable对象
- 自己写了一个链表功能还不完善但是简单的增删改查功能都已经实现了
- 自己动手实现一个简单的JSON解析器
- 将十进制整形数转换成二进制,然后通过字符型输出 自己实现的一个简单的例子
- 自己用 Netty 实现一个简单的 RPC
- 自己动手实现一个简单的Ajax
- 自己实现一个简单的Mybatis框架
- 自己实现的一个简单的数据库连接的插件————JdbcPlugin
- 自己实现一个简单的ArrayList
- 自己动手实现一个简单的string类(三)
- 想给自己制作一个简单的相册吗?快来看看 怎样实现3D图片相册效果
- 自己实现的一个简单的相册效果