#java #hashmap #graph-algorithm #hashset
#java #hashmap #граф-алгоритм #hashset
Вопрос:
У меня есть структура данных орграфа, которая использует представление списка ( HashMap<Vertex, ArrayList<Vertex>>
); исходная вершина в качестве ключа и список вершин назначения в качестве значения. Поиск в глубину и цикл dfs используются для обхода графика, чтобы найти порядок выполнения вершин.
Порядок выполнения задается как метка вершинного объекта, setLabel(int i)
и String name
для генерации используется только поле hashcode
.
Моя проблема в том, что после dfs
завершения и когда я перебираю ключи HashMap [ graph.keySet()
] , остается еще несколько вершин, которые не помечены, но когда я перебираю исследуемый набор, который является a HashSet<Vertex>
, все возможные вершины помечены (точно).
Что здесь может происходить? (Я могу использовать HashMap только для извлечения меток вершин)
Примечание: я считаю, что это имеет отношение к использованию изменяемых объектов в качестве ключей в хэш-картах. Если нет, пожалуйста, поправьте меня.
/**
* 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;
}}
Комментарии:
1. Примечание: я считаю, что это имеет отношение к использованию изменяемых объектов в качестве ключей в хэш-картах. Это звучит как разумное предположение. Вы пытались это исправить?
2. Примечание: вероятно, вам следует использовать
HashMap<Vertex, ArrayList<Vertex>>
вместо этого.3. Эй, необработанные типы. Пожалуйста, пожалуйста, никогда не используйте их.
4. Вы используете только
name
inhashCode
иequals
— этоfinal
значитHashMap
, что они должны быть счастливы.5. @Keppil Даже если объект Vertex является изменяемым, метка настройки не изменяет хэш-код. Поэтому я считаю, что это действительный ключ.
Ответ №1:
Проблема почти наверняка связана с управлением secondPass
переменной, поскольку именно это определяет, следует ли устанавливать метку:
if (!this.secondPass) {
start.setLabel( this.label);
}
Предоставленный вами код не показывает, где для этого будет установлено значение true.
Комментарии:
1. Нет. Я могу гарантировать, что он не изменится во время выполнения dfs. Приведенный выше код является частью 2-проходного алгоритма Kosaraju для вычисления SCCS, и this.SecondPass указывает, что это SecondPass и ничего более. В любом случае спасибо.