Procedure inorder(input: T) begin if T = nil then return; endif inorder(T --> left>; -- traverse the left subtree recursively visit(T); -- visit/process the root inorder(T --> right>; -- traverse the right subtree recursively end
Procedure preorder(input: T) begin if T = nil then return; endif visit(T); -- visit/process the root preorder(T --> left>; -- traverse the left subtree recursively preorder(T --> right>; -- traverse the right subtree recursively end
Procedure postorder(input: T) begin if T = nil then return; endif postorder(T --> left>; -- traverse the left subtree recursively postorder(T --> right>; -- traverse the right subtree recursively visit(T); -- visit/process the root end
Repeat the above two steps until no more nodes can be visited.
Procedure DFS(input: graph G) begin Stack S; Integer s,x; while (G has an unvisited node) do v := an unvisited node; visit(v); push(v,S); While (S is not empty) do x := top(S); if (x has an unvisited neighbor y) then visit(y); push(y,S); else pop(S); endif endwhile endwhile end
Procedure BFS(input: graph G) begin Queue Q; Integer s,x; while (G has an unvisited node) do s := an unvisited node; visit(s); Enqueue(s,Q); While (Q is not empty) do x := Dequeue(Q); For (unvisited neighbor y of x) do visit(y); Enqueue(y,Q); endfor endwhile endwhile end
V. Biconnectivity: A Major Application of DFS
Let (x,y) be a dashed edge between nodes that are not ancestor-descendent, that is, x and y are in separate subtrees of the DFS tree. Assume x was visited before y.
At the very last time (say time t) when a search for unvisited neighbors of x was conducted and none found, x was backtracked from, never to return to x again.
Well, since x is visited before y and y is not a descendent of x, y has not been visited at time t.
But since y is a neighbor of x and y is not visited at time t, y would have to be visited from x before the algorithm backtracks from x. That would make y a descendent of x. Contradiction.
Therefore, no such cross edge (x,y) can exist in a DFS tree. Q.E.D.
L[w]=the DFN of the highest node reachable from
L[w]=min{DFN[y] where y is w or is reachable from
L[w]=min{DFN[w], min{DFN[y] | where y is reachable from w}, {L[v]|v is a child of w}}
Procedure DFS(input: graph G,) begin Stack S; Integer s,x; Integer DFN[1:n], L[1:n], Parent[1:n]; Integer num := 1; v := an unvisited node; visit(v); push(v,S); DFN[v] := num; num++; L[v] := DFN[v]; While (S is not empty) do x := top(S); if (x has an unvisited neighbor y) then visit(y); push(y,S); DFN[y] := num; num++; Parent[y] := x; L[y] := DFN[y]; else pop(S); for (every neighbor y of x) do if (y != parent[x] and DFN[y] < DFN[x]) then /* y is an ancestor of x, and (x,y) is a back edge*/ L[x] := min(L[x],DFN[y]); else if (x = Parent[y]) then L[x] : min(L[x],L[y]); if (L[y] >= DFN[x] and x is not root) then x is an articulation point; endif endif endif endfor endif endwhile if (v has more than one child) then v is an articulation point; endif end
The new statements add constant-time operations except for the new for loop at the time of backtracking.
This new for-loop crosses the edges one more time to update the L values and check for articulation points. This increases the time by another O(|E|).
The final if-statement to check for the status of the root can be done by scanning the Parent array to count the number of children of the root s ( by counting the number of nodes whose Parent is s). This takes O(n) = O(|E|) time.
Therefore, the time complexity of the whole algorithm is O(|E|).