我写了一个名为Node的类。我重写了它的hashCode()函数,以考虑Node的两个字段(还有第三个字段不影响我的hashCode()函数)。我还写了一个equals()函数,它考虑了所有三个字段。
我正在尝试使用Hashtable类来存储节点,这样我可以在以后创建新节点时轻松检查新节点是否与哈希表中的节点重复。到目前为止我有这个
Hashtable<Node,Node> hashTbl = new Hashtable<Node,Node>();
...
Node node1 = // some new node
hashTbl.put(node1,node1);
...
现在,假设我创建了一个名为node2的新节点,它具有与node1完全相同的散列值,但不等于equals()方法定义的node1。我想检查node2是否与哈希表中的任何内容重复(它不是),但是如果我使用constainsKey(),那不会给我一个误报吗?似乎使用containsValue()不会利用哈希表的效率。那我怎么能有效地做到这一点呢?
另外,我的假设是当我调用hashTbl.put(arg1,arg2)时,它调用arg1的hashCode()函数并使用该值在“数组”中查找索引以放置arg2。这是对?
抱歉有点混乱。谢谢任何人。
答案 0 :(得分:3)
首先,你可能想要一个HashSet(或类似的东西),而不是Hashtable - 你要做的就是检查成员资格,而HashSet将允许你这样做而不需要为每个键提供一个值。
要回答您的问题,请确定数组中放入值的哪个插槽,但每个插槽实际上都是一个链接列表。如果新密钥不是.equal
链接列表中的任何其他密钥,则新密钥和值将放入链接列表中的自己的节点中。简单地为所有对象返回1是完全合法且正确的.hashcode
实现。该实现的唯一问题是它将Hashtables和类似的数据结构转换为链接列表(这显然会导致您失去Hashtable的所有性能优势)。
简而言之,您的.hashcode
方法可以正常使用。如果您放置了大量不是.equal
但具有相同哈希码的对象,性能将会降低,但代码仍然可以正常运行。
答案 1 :(得分:1)
你基本上是正确的:哈希表(顺便说一句,HashMap是更新的,更推荐的类)使用hashCode()
来找到一个桶来放置你的对象。如果有碰撞(另一个对象)在同一个桶中,它使用每个桶中的列表,使用equals(Object)
来确定这个新对象是否已经等于哈希中的一个对象(或者,在查找中,查看是否查找key匹配其中一个键值对)。因此,在所有冲突的最坏情况下,您的哈希变为具有O(N)运算的列表。正如你所指出的,这是低效的。
只要你的equals(Object)
是正确的,就不存在功能问题 - 如果你的hashCode产生太多冲突,那就是效率问题。基本上,如果两个对象相等,它们必须具有相同的hashCode才能正确;如果两个对象不相等,则它们应具有不同的hashCodes以实现散列效率。
答案 2 :(得分:0)
HashTable(或HashMap)包含N个bin,其中bin可以容纳多个Object。 (每个bin实际上是Map.Entry的链接列表)。密钥的hashCode()用于确定bin。但是,在确定bin之后,然后在键上使用equals()以查看该键是否已存在。因此,如果将node1和node2放入HashTable,并且两者都具有相同的hashCode()但不相等,它们将进入同一个bin,但该bin将是一个长度为2的链表,带有两个键,node1和node2,以及相应的值。
containsKey()不会给你一个误报,因为它会使用hashCode()来查找bin,但是然后会对该bin的所有键执行等于。对一堆密钥使用相同的hashCode会使HashTable变慢且效率低(如果所有值都具有相同的hashCode,实际上,您将存储在链表中)但不会破坏合同。