I am looking for an iterative version of graph post-order traversal in java. I have written the code to do iterative DFS. How could I modify the code so that the following code can print out the path of iterative post-order DFS traversal? For example, the output of the following graph should be 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);
}
}
}
}
Your graph is a directed graph, you cannot go from F
to any other node then, DFS from F
return only the F
node. In general, the output is different when you use different starting node (and if the graph is directed or not).
Iterative DFS algorithm could be written as:
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;
}
You could avoid the visited
Set
but use result
to check if a node was visited take O(n)
time when Set
take O(1)
(amortized).
A complete example:
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());
}
}
With output:
From 'F': F
From 'G': G, F
From 'A': A, B, C, F, D, E
If you wish postorder (show first the last visited node) reverse the result list (or add to head, etc.).
To reverse the children
order do not reverse before insert:
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;
}
Now, you get CBFEDA
:
From 'F': F
From 'G': F, G
From 'A': C, B, F, E, D, A
NOTE you example is wrong since after E
node you must visit F
not B
.