您好我正在使用由HashMap支持的Set来跟踪我在图表中已经遍历的边缘。 我计划通过添加存储在每个边缘的数据的哈希码来键入该集合。
v.getData().hashCode() + wordV.getData().hashCode()
但是当使用contains检查边缘是否在集合中时,这有多可靠?我不能假设得到误报吗?无论如何要克服这个问题吗?
引起我关注的确切陈述是:
edgeSet.contains(v.getData().hashCode() + wordV.getData().hashCode())
谢谢!
哦,就像我使用Java一样。
编辑:
我应该在问题中明确这一点。在我的图形中没有边缘对象,有顶点对象,每个顶点对象包含更多顶点对象的列表,即边缘。因此,我认为结合您的回答后面的问题是:
我可以使用Set来存储信息的引用而不是对象....? 即我可以存储为顶点的数据对象添加两个哈希码的结果吗?
EDIT2:
我确实在我的hashmap中使用Java库,我将其声明如下:
Set<Integer> edgeSet = Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());
答案 0 :(得分:6)
注意:根据您的问题,我无法判断您是使用HashSet
还是自己的家庭滚动实施。请注意,Java的HashSet
只是HashMap
的包装器,其中值被忽略。 HashSet.contains
只需在内部地图上调用containsKey
。
HashMap.containsKey
使用与get
相同的查找。这将计算哈希值并使用它来查找正确的桶。从那里它将走在桶中并使用equals
直到找到完全匹配。假设元素类型正确地实现了hashCode
和equals
,那么使用containsKey
就不会产生误报,因为equals
最终用于确认。
relevant source code位于包私有方法getEntry
中,由containsKey
和get
使用:
final Entry<K,V> getEntry(Object key) {
int hash = (key == null) ? 0 : hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
修改强>
我可以使用Set来存储对信息的引用,而不是 对象....?即我可以存储添加两个哈希码的结果 顶点的数据对象?
不,您需要实现一个表示此信息的新类,并将其实例存储在Set
中。这可以是一个简单的POJO,其中包含每条信息的字段,并且正确覆盖hashCode
和equals
。
答案 1 :(得分:5)
根据定义,散列码会发生冲突。将它们添加在一起无助于此。
您应该使图形的边缘支持hashCode和equals,并且只需将边缘放在哈希集中即可。
class Edge { ... equals and hashCode ... }
HashSet<Edge> traversed = new HashSet<Edge>();
traversed.add(edge);
...
if(traversed.contains(edge)) ...
如果你正在为你的边编号,那么Integer已经有一个好的哈希码并且等于,所以使用它:
HashSet<Integer> traversed = new HashSet<Integer>();
if(traversed.contains(edgeNumber)) ...
traversed.add(3);
答案 2 :(得分:1)
只要您同时覆盖hashCode()
和equals()
,就可以了。哈希码永远不会保证是唯一的。那就是说,你有点滥用Set。通过使用正确实施的hashCode()
和equals()
方法存储类,contains()
'等方法将具有完美的准确性。但是,这不是你在这里使用它的方式。听起来你几乎正在构建自己的数据结构/集合,你需要考虑这样做,就像'Hash'集合那样 - 使用HashMap来存储哈希的桶 - 哈希值作为key,然后是要比较的值的集合。这将允许您快速查看父地图是否具有您正在寻找的哈希。如果没有,你就完成了(假)。如果是,那么您需要确认其“桶”具有您正在寻找的特定值(true)。