1

我有一个在我们的例子中称为规则的对象列表,这个对象本身是一个字段列表,我必须对其进行哈希码比较,因为我们不能在系统中复制规则。

即假设我有两个规则 R1 和 R2 与字段 A 和 B。

现在,如果 R1 中 A 和 B 的值分别为 7 和 2。

在 R2 中它分别是 3 和 4 然后我用来检查系统中规则的重复性的过程是哈希码比较失败

我使用的方法是

for(Rule rule : rules){
changeableAttrCode=0;

fieldCounter=1;

attributes = rule.getAttributes();

for(RuleField ruleField : attributes){

changeableAttrCode = changeableAttrCode + (fieldCounter * ruleField.getValue().hashCode());

fieldCounter++;

}
parameters = rule.getParameters();

for(RuleField ruleField : parameters){

changeableAttrCode = changeableAttrCode + (fieldCounter * ruleField.getValue().hashCode());

fieldCounter++;

}

changeableAttrCodes.add(changeableAttrCode);

这里 changeableAttrCodes 我们存储所有规则的哈希码。

所以请给我建议更好的方法,这样以后就不会出现这种问题,并且可以看到系统中规则的重复性。

提前致谢

4

5 回答 5

5

hashcode()不是用来检查相等性的。return 42;是一个完全有效的实现hashcode()。为什么不在规则对象中覆盖equals()(并且hashcode()就此而言)并使用它来检查两个规则是否相等?您仍然可以使用哈希码来检查您需要调查哪些对象,因为两个equal()对象应该始终具有相同的哈希码,但这是您可能需要也可能不需要的性能改进,具体取决于您的系统。

于 2010-02-25T11:00:05.363 回答
4
  • 实施hashCodeequals课堂规则。
  • 实现equals必须比较它的值。

然后使用 aHashSet<Rule>并询问if(mySet.contains(newRule))

HashSet + equals 的实现解决了哈希的非唯一性问题。它使用散列进行分类和速度,但它在最后使用等于来确保具有相同散列的两个规则是相同的规则。

有关 hash 的更多信息:如果您想手动完成,请使用质数建议,并查看 JDK 代码以获取字符串哈希码。如果你想要一个干净的实现尝试检索元素的哈希码,制作某种整数数组并使用 Arrays.hashCode(int[]) 获取它们组合的哈希码。

于 2010-02-25T11:00:50.603 回答
3

更新您的散列算法没有产生良好的散列值分布 - 它为 (7, 2) 和 (3, 4) 提供相同的值:

1 * 7 + 2 * 2 = 11
1 * 3 + 2 * 4 = 11

它还会为 (11, 0), (-1, 6), ... 提供相同的值,并且可以根据您当前的算法轻松组成无数类似的等价类。

当然你不能避免冲突——如果你有足够的实例,哈希冲突是不可避免的。但是,您的目标应该是尽量减少发生碰撞的机会。好的散列算法努力将散列值平均分布在广泛的值范围内。实现此目的的典型方法是为包含n 个独立字段的对象生成哈希值,作为n位数字,其基数大到足以容纳各个字段的不同哈希值。

在你的情况下,而不是乘以fieldCounter你应该乘以一个素数常数,例如 31(这将是你的数字的基数)。并在结果中添加另一个素数常数,例如 17。这可以让您更好地散列散列值。(当然,具体的基础取决于您的字段可以采用什么值 - 我没有这方面的信息。)

此外,如果您实施hashCode,强烈建议您也实施equals- 事实上,您应该使用后者来测试是否相等。

这是一篇关于实现hashCode的文章。

于 2010-02-25T10:59:49.477 回答
2

我不明白你想在这里做什么。在大多数散列函数场景中,冲突是不可避免的,因为要散列的对象比可能的散列值要多得多(这是鸽巢原则)。

通常情况下,两个不同的对象可能具有相同的哈希值。您不能仅依靠哈希函数来消除重复项。

一些散列函数在最小化冲突方面比其他函数更好,但这仍然是不可避免的。


也就是说,有一些简单的准则通常可以提供足够好的散列函数。Joshua Bloch 在他的《Effective Java 2nd Edition》一书中给出了以下内容:

  • int在名为 的变量中存储一些恒定的非零值,例如 17 result
  • 计算每个字段 的int哈希码:c
    • 如果字段是 a boolean,计算(f ? 1 : 0)
    • 如果字段是 a byte, char, short, int,计算(int) f
    • 如果字段是 a long,计算(int) (f ^ (f >>> 32))
    • 如果字段是 a float,计算Float.floatToIntBits(f)
    • 如果该字段是 a double,则计算Double.doubleToLongBits(f),然后像上面一样对结果进行哈希处理long
    • 如果该字段是对象引用并且此类的equals方法通过递归调用来比较该字段,则在该字段上equals递归调用hashCode。如果该字段的值为null,则返回 0。
    • 如果该字段是一个数组,则将其视为每个元素都是一个单独的字段。如果数组字段中的每个元素都很重要,则可以使用Arrays.hashCode1.5 版中添加的方法之一。
  • 将hashcode组合cresult如下:result = 31 * result + c;
于 2010-02-25T10:59:53.167 回答
0

我开始写,你可以实现你想要的唯一方法是使用Perfect Hashing

但后来我想到了你说你不能在你的系统中复制对象的事实。

根据 helios 发人深省的评论进行编辑:

您的解决方案取决于您在写“不能复制规则”时的意思。

如果你的意思是字面上你不能,保证只有一个具有一组特定值的规则实例,那么你的问题是微不足道的:你可以进行身份​​比较,在这种情况下,你可以使用 == 进行身份比较.

另一方面,你的意思是你不应该出于某种原因(性能),那么你的问题也是微不足道的:只做价值比较。

鉴于您定义问题的方式,在任何情况下都不应考虑使用哈希码来代替相等性。 正如其他人所指出的,哈希码本质上会产生冲突(错误相等),除非您使用完美哈希解决方案,但在这种情况下您为什么要这样做?

于 2010-02-25T12:35:37.457 回答