具有容差级别的双精度的哈希方法



我实现了一个如下所示的等于方法,具有双精度的容差水平。

public boolean equals(Object obj) {
// Checking for not null and same class etc.
return approxEqual(this,other);
}
private static boolean approxEqual(final Position p1, final Position p2) {
double distance = // distance function between positions
return Double.compare(distance, TOLERANCE) <= 0;
}

当我使用HashSet时,我需要具有相同功能的哈希方法。 你们知道如何做到这一点吗?

我知道,容差水平不是很好,因为 equals 方法应该是传递的。但我需要平衡测量的不准确性。

假设:假设您的容差目前为 1。这意味着 0 等于 0.8,因为它们的差值小于容差。然后让我们比较 0.8 和 1.5,它们是相等的,因为它们的差值是 0.7 <1。这意味着他们将获得相同的哈希值,这意味着 0 和 1.5 具有相同的哈希值,重复该过程,所有内容都将获得相同的哈希值/相等。

这说不通,是吗?你不能宽容地做equalhashcode

不幸的是,我相信这违背了哈希的本质。

k-d树或二叉搜索是作为替代解决方案首先想到的。

使用TreeMap而不是HashMap

如果在compareTo/compare方法中实现容差,则任何键查找/插入都将"对齐"到容差范围内的现有键。

当然,仍然需要注意的是,插入顺序可能会影响结果。 例如,如果容差为 5,并且您有值 2、6 和 9,则先添加 6 会将 2 和 9 捕捉到 6 值,结果是一个键 (6),否则您最终得到两个键(2 和 9),并且 6 捕捉到 2 或 9 是任意的。

有了宽容,你真的对这种不可预测性无能为力,所以我相信这是解决你问题的最佳方法。

您可以将数据拆分为多个范围,并说某个范围内的所有内容都是相等的。
您可以通过舍入来执行此操作(确切的详细信息取决于您要查找的公差级别,对于以下内容,您可以简单地使用floor)。

因此,如果我们拆分为 1 的范围,我们可以说 0 到 1 之间的所有内容(不包括 1,即在[0,1)范围内)都是相等的,而 1 到 2 之间的所有内容都是相等的,依此类推。


然而,这确实会产生一个问题,即如果元素在不同的范围内,彼此非常接近的元素可能不相等,例如,对于上述内容,0.9999 将不被视为等于 1.0001。

如果您尝试仅使用相等(和哈希)来解决此问题,则此问题并非完全可以避免,因为扩展这些范围并不能解决此问题,并且尝试使它们重叠会产生新问题。

根据您尝试使用它的方式,可以通过执行多次查找来解决上述问题,因此您可以在 [0,1] 范围和 [1,2] 范围内考虑 0.9999。如果您说要尝试进行查找以查找其他元素的某种容差范围内的所有元素(这与将元素视为平等并不完全相同),这将起作用。

如果这对您不起作用,散列可能不是您正在寻找的解决方案,您可能需要考虑有序数据集,例如TreeMap(或者实际上是 kd 树,如另一个答案中所述)。


这主要基于 1D 数据(即双精度),但可以通过对每个维度进行舍入来轻松扩展到 2D(正方形范围)或 3D(立方体范围)。如果要执行上述多个查找,则可能需要执行的不是 1 次查找(最近的范围),而是在 2D 中最多执行 3 次查找(水平和垂直方向上最接近的正方形范围,以及与这两个范围相邻的正方形),对于 3D 也是如此。

最新更新