如何解决HashMap 创建重复键?
我有一个 Vertex
类定义为:
class Vertex {
private String s;
public Vertex(String s) {
this.s = s;
}
public String getName() {
return s;
}
public void setName(String s) {
this.s = s;
}
public boolean equals(Vertex o) {
return s.equals(o.getName());
}
@Override
public String toString() {
return s;
}
}
和具有以下方法的类 DirectedGraph
:
private HashMap<Vertex,HashSet<Vertex>> adjacencyMap = new HashMap<>();
public boolean addVertex(Vertex v) {
if (!this.adjacencyMap.containsKey(v)) {
this.adjacencyMap.put(v,new HashSet<>());
return true;
}
return false;
}
public boolean addEdge(Vertex x,Vertex y) {
if (adjacencyMap.containsKey(x) && adjacencyMap.containsKey(y)) {
if (!adjacencyMap.get(x).contains(y)) {
adjacencyMap.get(x).add(y);
edgeCount++;
return true;
}
}
return false;
}
public DirectedGraph(File f) throws FileNotFoundException {
Scanner s = new Scanner(f);
while (s.hasNextLine()) {
String l = s.nextLine();
int i = 0;
Vertex parent = null;
for (String t : l.split(" ")) {
if (i == 0) {
parent = new Vertex(t);
if (root == null) {
root = parent;
}
addVertex(parent);
} else {
Vertex v = new Vertex(t);
addVertex(v);
if (addEdge(parent,v) != true) System.out.println(parent + "," + v + "failed");
// System.out.println("adding edge: " + parent + "," + v);
}
i++;
}
}
s.close();
for (Vertex v : adjacencyMap.keySet()) {
System.out.println(v + ": \n " + adjacencyMap.get(v));
}
}
如您所见,它接受一个文件并逐行扫描它,假设第一个节点是“父”节点,而后面的节点依赖于它。如果我使用以下输入文本文件:
B D G
C A
E B F H
J B
I C
我的问题是我的输出是:
A:
[]
J:
[]
F:
[]
C:
[]
J:
[B]
B:
[]
C:
[]
G:
[]
E:
[F,B,H]
B:
[]
H:
[]
A:
[J,C,E]
I:
[C]
B:
[G,D]
D:
[]
E:
[]
C:
[A]
如您所见,我的 HashMap
有多个重复键,因为我一定不明白 containsKey
是如何工作的。我有两个想法来解决我的问题:
首先,更像洞穴人,是简单地迭代 keySet()
,手动比较顶点的名称,并组合 .get()
,或者
更新 addVertex 或 addEdge(以主要违规者为准)以识别重复键。
我不知道该怎么做,因此朝正确的方向推动将最有帮助。
解决方法
HashMap
使用散列函数计算用作 key
的对象的索引。为了使此功能正常工作,您需要为您打算用作哈希映射中键的类的实例提供 equals()
和 hashCode()
函数。
这意味着您需要覆盖现在直接从 public int hashCode()
超类继承的 Object
方法,并在那里放置一些计算,这些计算将为被视为“相等”的对象返回相同的整数。幸运的是,您将 String
作为此标准进行比较,因此您可以使用 String
方法 hashCode
,结果为:
@Override
public int hashCode() {
return s.hashCode();
}
我之前遗漏的第二个问题是您对 equals()
的实现是错误的。您应该 override
Object
的 equals()
具有签名 public boolean equals( Object o )
并且您使用 Vertex
作为参数实现它,这导致在添加到 hashmap { {1}} 的 Object
equalsequals was used,as you didn't override by overload
@Override. That's one of the reasons that annotation
equals` 正确....
should be used,compiler would tell you that you don't override anything and you would know that you're doing something wrong. Now,going back to how to implement
现在 @Override
public boolean equals(Object o) {
if( o instanceof Vertex ) {
return s.equals((( Vertex)o).getName());
} else {
return false;
}
}
的实例在用作哈希映射中的键时将正常运行。
顺便说一句,把所有的逻辑,包括打开,解析文件放在构造函数中有点不合我的口味,考虑把它拆分成一些方法。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。