HashMap 创建重复键?
HashMap creating duplicate keys?
我有一个 class 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;
}
}
和 class 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()
s,或
更新 addVertex 或 addEdge,以识别重复键为准,以识别重复键为准。
我不知道该怎么做,所以朝正确的方向推进会最有帮助。
HashMap
使用散列函数计算用作 key
的对象的索引。为了使此功能正常工作,您需要为 class 提供 equals()
和 hashCode()
函数,您的实例计划将其用作哈希映射中的键。
这意味着您需要覆盖现在直接从 Object
superclass 继承的 public int hashCode()
方法,并在那里进行一些计算,这些计算将 return 被认为是对象的相同整数 'equal'。幸运的是,您将 String
s 作为此标准进行比较,因此您可以使用 String
方法 hashCode
结果:
@Override
public int hashCode() {
return s.hashCode();
}
我之前遗漏的第二个问题是您对 equals()
的实现是错误的。您应该 override
Object
的 equals()
具有签名 public boolean equals( Object o )
并且您使用 Vertex
作为参数实现它,这导致在添加到 hashmap Object
的equals was used, as you didn't override by overload
等于. That's one of the reasons that annotation
@Overrideshould 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;
}
}
现在 Vertex
的实例在用作哈希映射中的键时会正常运行。
附带说明一下,将所有逻辑(包括打开、解析文件)放在构造函数中对我来说有点太多了,请考虑将其拆分为一些方法。
我有一个 class 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;
}
}
和 class 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()
s,或
更新 addVertex 或 addEdge,以识别重复键为准,以识别重复键为准。
我不知道该怎么做,所以朝正确的方向推进会最有帮助。
HashMap
使用散列函数计算用作 key
的对象的索引。为了使此功能正常工作,您需要为 class 提供 equals()
和 hashCode()
函数,您的实例计划将其用作哈希映射中的键。
这意味着您需要覆盖现在直接从 Object
superclass 继承的 public int hashCode()
方法,并在那里进行一些计算,这些计算将 return 被认为是对象的相同整数 'equal'。幸运的是,您将 String
s 作为此标准进行比较,因此您可以使用 String
方法 hashCode
结果:
@Override
public int hashCode() {
return s.hashCode();
}
我之前遗漏的第二个问题是您对 equals()
的实现是错误的。您应该 override
Object
的 equals()
具有签名 public boolean equals( Object o )
并且您使用 Vertex
作为参数实现它,这导致在添加到 hashmap Object
的equals was used, as you didn't override by overload
等于. That's one of the reasons that annotation
@Overrideshould 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;
}
}
现在 Vertex
的实例在用作哈希映射中的键时会正常运行。
附带说明一下,将所有逻辑(包括打开、解析文件)放在构造函数中对我来说有点太多了,请考虑将其拆分为一些方法。