提交 f986f6ae authored 作者: Thomas Mueller's avatar Thomas Mueller

Minimal perfect hash tool

上级 2d649ea2
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.unit;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import org.h2.dev.hash.IntPerfectHash;
import org.h2.dev.hash.IntPerfectHash.BitArray;
import org.h2.test.TestBase;
/**
* Tests the perfect hash tool.
*/
public class TestIntPerfectHash extends TestBase {
/**
* Run just this test.
*
* @param a ignored
*/
public static void main(String... a) throws Exception {
TestIntPerfectHash test = (TestIntPerfectHash) TestBase.createCaller().init();
test.measure();
test.test();
test.measure();
}
/**
* Measure the hash functions.
*/
public void measure() {
int size = 10000;
test(size / 10);
int s;
long time = System.currentTimeMillis();
s = test(size);
time = System.currentTimeMillis() - time;
System.out.println((double) s / size + " bits/key in " +
time + " ms");
}
@Override
public void test() {
testBitArray();
for (int i = 0; i < 100; i++) {
test(i);
}
for (int i = 100; i <= 10000; i *= 10) {
test(i);
}
}
private void testBitArray() {
byte[] data = new byte[0];
BitSet set = new BitSet();
for (int i = 100; i >= 0; i--) {
data = BitArray.setBit(data, i, true);
set.set(i);
}
Random r = new Random(1);
for (int i = 0; i < 10000; i++) {
int pos = r.nextInt(100);
boolean s = r.nextBoolean();
data = BitArray.setBit(data, pos, s);
set.set(pos, s);
pos = r.nextInt(100);
assertTrue(BitArray.getBit(data, pos) == set.get(pos));
}
assertTrue(BitArray.countBits(data) == set.cardinality());
}
private int test(int size) {
Random r = new Random(size);
HashSet<Integer> set = new HashSet<Integer>();
while (set.size() < size) {
set.add(r.nextInt());
}
ArrayList<Integer> list = new ArrayList<Integer>();
list.addAll(set);
byte[] desc = IntPerfectHash.generate(list);
int max = test(desc, set);
assertEquals(size - 1, max);
return desc.length * 8;
}
private int test(byte[] desc, Set<Integer> set) {
int max = -1;
HashSet<Integer> test = new HashSet<Integer>();
IntPerfectHash hash = new IntPerfectHash(desc);
for (int x : set) {
int h = hash.get(x);
assertTrue(h >= 0);
assertTrue(h <= set.size() * 3);
max = Math.max(max, h);
assertFalse(test.contains(h));
test.add(h);
}
return max;
}
}
...@@ -76,6 +76,12 @@ public class MinimalPerfectHash<K> { ...@@ -76,6 +76,12 @@ public class MinimalPerfectHash<K> {
*/ */
private static final int DIVIDE = 6; private static final int DIVIDE = 6;
/**
* For sets larger than this, instead of trying to map then uniquely to a
* set of the same size, the size of the set is incremented by one. This
* reduces the time to find a mapping, but the index of the hole also needs
* to be stored, which increases the space usage.
*/
private static final int SPEEDUP = 11; private static final int SPEEDUP = 11;
/** /**
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论