我将大量具有地理位置的对象存储为以米为单位的2D点(x,y)。为了代表世界,我使用的网格划分为1平方公里的单元格。目前我正在使用HashMap<Position, Object>
。任何其他地图或适当的数据结构都可以,但我的解决方案是有效的,所以我只对解决细节感兴趣。
我一直在阅读很多关于制作好的哈希函数的内容,特别是2D点。到目前为止,没有任何解决方案真的很好(尽可能无碰撞地评价)。
为了测试一些想法,我写了一个非常简单的java程序,为从任意数字(-1000,-1000)到(1000,1000)(x1,y1 - &gt; x2,y2)的点生成哈希码并存储他们在HashSet<Integer>
中,这是我的结果:
# java HashTest
4000000 number of unique positions
test1: 3936031 (63969 buckets, 1,60%) collisions using Objects.hash(x,y)
test2: 0 (4000000 buckets, 100,00%) collisions using (x << 16) + y
test3: 3998000 (2000 buckets, 0,05%) collisions using x
test4: 3924037 (75963 buckets, 1,90%) collisions using x*37 + y
test5: 3996001 (3999 buckets, 0,10%) collisions using x*37 + y*37
test6: 3924224 (75776 buckets, 1,89%) collisions using x*37 ^ y
test7: 3899671 (100329 buckets, 2,51%) collisions using x*37 ^ y*37
test8: 0 (4000000 buckets, 100,00%) collisions using PerfectlyHashThem
test9: 0 (4000000 buckets, 100,00%) collisions using x << 16 | (y & 0xFFFF)
图例:碰撞次数,存储量(碰撞次数),perc(碰撞次数)
这些散列函数中的大多数都表现得很糟糕。事实上,唯一的好处是将x移位到整数的前16位。我想,限制是两个最远点不得超过Integer.MAX_INT
的平方根,即面积必须小于46 340平方公里。
这是我的测试函数(只为每个新的哈希函数复制):
public void test1() {
HashSet<Integer> hashCodes = new HashSet<Integer>();
int collisions = 0;
for (int x = -MAX_VALUE; x < MAX_VALUE; ++x) {
for (int y = -MAX_VALUE; y < MAX_VALUE; ++y) {
final int hashCode = Objects.hash(x,y);
if (hashCodes.contains(hashCode))
collisions++;
hashCodes.add(hashCode);
}
}
System.console().format("test1: %1$s (%2$s buckets, %3$.2f%%) collisions using Objects.hash(x,y)\n", collisions, buckets(collisions), perc(collisions));
}
我在这里错了吗?我应该微调素数以获得更好的结果吗?
编辑:
添加了更多哈希函数(test8和test9)。 test8来自@nawfal在Mapping two integers to one, in a unique and deterministic way的响应(从short转换为int)。
答案 0 :(得分:1)
public void test1() {
int MAX_VALUE = 1000;
HashSet<Integer> hashCodes = new HashSet<Integer>();
int collisions = 0;
for (int x = -MAX_VALUE; x < MAX_VALUE; ++x) {
for (int y = -MAX_VALUE; y < MAX_VALUE; ++y) {
final int hashCode = ((x+MAX_VALUE)<<16)|((y+MAX_VALUE)&0xFFFF);
if (hashCodes.contains(hashCode))
collisions++;
hashCodes.add(hashCode);
}
}
System.out.println("Collisions: " + collisions + " // Buckets: " + hashCodes.size());
}
打印:碰撞:0 //铲斗:4000000
答案 1 :(得分:1)
我是一个类似的问题,答案是使用Cantor配对功能。这里: Mapping two integers to one, in a unique and deterministic way
Cantor配对函数也可以用于负整数,使用双射。