Busco a una versión iterativa del recorrido del grafo posterioridad a la orden java. He escrito el código para hacer DFS iterativos. ¿Cómo podría modificar el código para que el código siguiente se puede imprimir el camino de la post-fin iterativo DFS recorrido? Por ejemplo, la salida del siguiente gráfico debe ser FCBEDA (G).
public void DFS(int sourceVertex) {
Stack<Integer> stack = new Stack<>();
stack.push(sourceVertex);
while (!stack.isEmpty()) {
int v = stack.pop();
if (!marked[v]) {
marked[v] = true;
for (int w : v.adj) {
stack.push(w);
}
}
}
}
Su gráfico es un grafo dirigido, no se puede ir de F
a cualquier otro nodo a continuación, DFS de F
retorno sólo el F
nodo. En general, la salida es diferente cuando se utiliza diferente nodo de partida (y si el gráfico está dirigida o no).
Iterativo DFS algoritmo podría ser escrito como:
static List<Node> DFS(Node n) {
Stack<Node> current = new Stack<>();
Set<Node> visited = new HashSet<>(); // efficient lookup
List<Node> result = new ArrayList<>(); // ordered
current.push(n);
while(!current.isEmpty()) {
Node c = current.pop();
if(!visited.contains(c)) {
result.add(c);
visited.add(c);
// push in reversed order
IntStream.range(0, c.getChildren().size())
.forEach(i -> current.push(c.getChildren().get(c.getChildren().size() - i - 1)));
}
}
return result;
}
Se podría evitar el visited
Set
sino que lo utiliza result
para comprobar si un nodo fue visitado toma O(n)
momento en que Set
toma O(1)
(amortizado).
Un ejemplo completo:
public static void main(String[] args) {
Node A = new Node("A");
Node B = new Node("B");
Node C = new Node("C");
Node D = new Node("D");
Node E = new Node("E");
Node F = new Node("F");
Node G = new Node("G");
A.getChildren().addAll(asList(B, D));
B.getChildren().addAll(asList(C));
C.getChildren().addAll(asList(F));
D.getChildren().addAll(asList(B, F, E));
E.getChildren().addAll(asList(F));
//F.getChildren().addAll(asList());
G.getChildren().addAll(asList(F));
testDFS(F);
testDFS(G);
testDFS(A);
}
static class Node {
private final String label;
private final List<Node> children;
Node(String label) {
this.label = label;
this.children = new ArrayList<>();
}
public String getLabel() {
return label;
}
public List<Node> getChildren() {
return children;
}
@Override
public int hashCode() {
return getLabel().hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Node))
return false;
return getLabel().equals(((Node) obj).getLabel());
}
}
Con salida:
From 'F': F
From 'G': G, F
From 'A': A, B, C, F, D, E
Si desea orden posterior (mostrar primero el último nodo visitado) revertir la lista de resultados (o agregar a la cabeza, etc.).
Para invertir el children
orden no invierta antes de insertar:
static List<Node> DFSreversedPostOrder(Node n) {
Stack<Node> current = new Stack<>();
Set<Node> visited = new HashSet<>(); // efficient lookup
List<Node> result = new ArrayList<>(); // ordered
current.push(n);
while(!current.isEmpty()) {
Node c = current.pop();
if(!visited.contains(c)) {
result.add(0, c);
visited.add(c);
c.getChildren().forEach(current::push);
}
}
return result;
}
Ahora, se obtiene CBFEDA
:
From 'F': F
From 'G': F, G
From 'A': C, B, F, E, D, A
NOTA que está mal ejemplo ya que después de E
nodo que debe visitar F
no B
.