【问题标题】:Using mutable objects as keys in HashMaps在 HashMaps 中使用可变对象作为键
【发布时间】:2014-06-29 12:25:26
【问题描述】:

我有一个使用列表表示的有向图数据结构(HashMap<Vertex, ArrayList<Vertex>>);源顶点作为键,目标顶点的 ArrayList 作为值。深度优先搜索和 dfs 循环用于遍历图以找到顶点的执行顺序。

执行顺序由setLabel(int i)设置为Vertex对象的标签,并且只有String name字段用于生成hashcode

我的问题是,dfs 完成后,当我遍历 HashMap [graph.keySet()] 的键时,仍然有几个没有标记的顶点,但是当我迭代时虽然探索的集合是aHashSet<Vertex>,但所有可能的顶点都被标记(准确地)。

这里可能发生什么? (我只能使用 HashMap 来检索顶点的标签)

注意:我相信这与在 HashMaps 中使用可变对象作为键有关。如果不是请纠正我。

 /**
 * Recursive depth-first search     
 * @param graph HashMap<Vertex,ArrayList> (list representation)
 * @param start starting Vertex
 */
public void dfsR(HashMap<Vertex, ArrayList<Vertex>> graph, Vertex start) {
    this.explored.add(start); //a HashSet<Vertex>        

    ArrayList<Vertex> list = graph.get(start);
    if (list != null) {
        for (Vertex v : list) {
            if (!this.explored.contains(v)) {
                this.dfsR(graph, v);
            }
        }
    }
    /* First pass-Execution order */
    if (!this.secondPass) {
        start.setLabel(++this.label);
    }
}

 /**
 * Run DFS on every vertex of the Graph      
 * @param graph HashMap<Vertex,ArrayList<Vertex>> (list representation)
 */
private void dfsLoop(HashMap<Vertex, ArrayList> graph) {
    this.secondPass = false;
    this.explored.clear();        
    this.label = 0;
    for (Vertex vertex : graph.keySet()) {
        if (!this.explored.contains(vertex)) {
            this.dfsR(graph, vertex); /* Recursive dfs */                                
        }
    }
}

public class Vertex {

private final String name;
private int label;    

public Vertex(String name) {
    this.name = name;
    this.label = -1;
}

public Vertex(Integer name) {
    this.name = String.valueOf(name);
    this.label = -1;
}

public String getName() {
    return name;
}

/**
 * Value(Label) obtained from Topological Ordering  
 * @param label integer value of the relevant position
 */
public void setLabel(int label){
    this.label = label;
}

/** 
 * @return the Label obtained from the Topological ordering
 */
public int getLabel(){
    return this.label ;
}    

@Override
public String toString() {
    return name;
}

@Override
public boolean equals(Object o) {
    if(o == null){
        return false;
    }
    if (o instanceof Vertex) {
        Vertex v = (Vertex) o;
        return this.name.equals(v.getName());
    }
    return false;
}

@Override
public int hashCode() {
    int hash = 3;       
    hash = 89 * hash + this.name.hashCode();
    return hash;
}}

【问题讨论】:

  • 注意:我相信这与在 HashMaps 中使用可变对象作为键有关。 这听起来像是一个合理的猜测。您是否尝试过纠正此问题?
  • 注意:您可能应该改用HashMap&lt;Vertex, ArrayList&lt;Vertex&gt;&gt;
  • Eug 原始类型。请不要使用它们。
  • 您只在hashCodeequals 中使用name - 这是final 所以HashMap 应该很高兴。
  • @Keppil 即使 Vertex 对象是可变的,设置标签也不会改变 hashCode。所以我相信它是有效的密钥。

标签: java hashmap graph-algorithm hashset


【解决方案1】:

这个问题几乎肯定与secondPass 变量的管理有关,因为它控制着是否设置标签:

if (!this.secondPass) {
    start.setLabel(++this.label);
}

您提供的代码没有显示设置为 true 的位置。

【讨论】:

  • 没有。我可以保证在执行 dfs 期间它不会改变。上面的代码是 Kosaraju 用于计算 SCC 的 2-pass 算法的一部分,this.secondPass 表示它是 secondPass,仅此而已。无论如何,谢谢。
猜你喜欢
  • 1970-01-01
  • 2011-03-08
  • 2019-07-16
  • 2021-10-23
  • 1970-01-01
  • 2013-08-06
  • 1970-01-01
  • 2015-05-13
  • 2018-01-30
相关资源
最近更新 更多