Abstract

Explore is the same algorithm as Graph Search where is a Stack. The main difference is that Graph Search is a Mid-Level Implementation while Explore is a Low-Level Implementation of Graph Search.

  • Category: Graph Traversal (single-component reachability)
  • Input: Graph , source vertex
  • Output: visited array; optionally prev, pre, post for path/timestamp tracking
  • Paradigm: Recursion (implicit stack, FILO order)
  • Typical use cases: the recursive building block used inside Depth First Search (DFS); single-source reachability queries

Core Logic: Recursive Stack-Based Search

Explore vs. DFS

The explore algorithm uses the same underlying logic as Depth First Search (DFS) and undergoes a FILO scheme. The difference lies in Explore will not visit any nodes that are disconnected from the starting vertex; whereas DFS continues to search in disconnected vertices after fully exploring the current sub-graph.

  1. Mark the current vertex s as visited.
  2. For each edge (s, u) out of s, if u is unvisited, recursively call explore on u.
  3. Once every neighbor has been checked (and their subtrees fully explored), the call returns — this is the “leaving the stack” moment.

Key Idea

explore is the recursion, and the call stack is the stack F from Graph Search — there’s no separate data structure to manage, the language runtime does it for you.


Pseudocode (Mid-Level Implementation)

Graph Search (general form, for comparison)

Algorithm 31 Graph Search

procedure GraphSearch(G,sG, s)

XX = empty, FF = {s}\{ s \}, U=VFU = V - F

while FF is not empty do

Pick vv in FF

for all neighbors uu of vv do

if u∉Xu \not\in X or FF then

move uu from UU to FF

move vv from FF to XX

return X

Explore (low-level implementation of Graph Search, = stack)

Algorithm 32 Explore

procedure explore(G=(V,E),sG = (V, E), s)

visited(ss) = true

for each edge (s,u)(s, u) do

if not visited(uu) then

explore(G,uG, u)

The output is an array visited such that visited(u) is true if and only if is reachable from , for all vertices .

Important

This implementation only gives information about whether there is a path from to another vertex. However, sometimes it is helpful to know what those paths are.

Variables & Data Structures

NameTypePurpose
visitedBoolean arrayMarks whether a vertex has been discovered, preventing infinite loops on cycles
(implicit)Call stackPlays the role of F from Graph Search — FILO order gives depth-first behavior
prevArray (vertex → vertex)(path-tracking version) Records the discovery edge for each vertex
pre, postArray (vertex → int)(path-tracking version) Timestamps for when a vertex enters/leaves the stack
clockInteger counter(path-tracking version) Global tick used to generate pre/post values

Helper Functions / Operations Used

  • explore(G, u) — recursive call; the “push” onto the stack happens implicitly via the function call
  • previsit(v) — called when v enters the stack; sets pre(v) = clock and increments clock
  • postvisit(v) — called when v leaves the stack; sets post(v) = clock and increments clock

Optional Low-Level Implementation: Keep Track of Paths

We can include another array of information. Set prev(u) to be the “parent” of u in the DFS output tree. By also tracking when a node enters (pre) and leaves (post) the stack, we can know the connected structure of directed graphs.

Algorithm 33 Explore with Path Record

procedure explore(G=(V,E),sG = (V, E), s)

visited(ss) = true

previsit(ss)

for each edge (s,u)(s, u) do

if not visited(uu) then

prev(uu) = ss

explore(G,uG, u)

postvisit(ss)

Algorithm 34 previsit

procedure previsit(vv)//when vertex vv enters the stack

pre(vv) = clock

clock++

Algorithm 35 postvisit

procedure postvisit(vv)//when vertex vv leaves the stack

post(vv) = clock

clock++

DFS Output Tree

A DFS output tree is the tree structure formed by the edges in the prev array after Explore has been performed on a graph. When explore discovers an unvisited neighbor u from vertex s, it records prev(u) = s — “I reached u by traveling the edge (s, u).” Collecting all such discovery edges across the entire Explore gives the output tree — it contains only the edges Explore actually used to find new vertices. Any edge that led to an already-visited vertex is discarded.

  • Connected graph → a single DFS output tree, rooted at the first vertex explored
  • Disconnected graph → a DFS Output Forest, one tree per connected component, each rooted at the vertex that triggered cc++

Example: If DFS visits A → B → D → C, the output tree contains edges A–B, B–D, and D–C. Any edge encountered along the way that pointed to an already-visited vertex is not included.


Proof of Correctness

Claim: Upon termination of explore(G, s), visited(u) = True if and only if u is reachable from s (i.e. visited correctly computes the connected component containing s).

() Nothing unreachable is ever marked visited: explore only ever recurses along an actual edge (s, u) \in E. By induction on the recursion depth, every call explore(G, v) is only ever reached by following a chain of real edges starting from s, so every vertex marked visited is reachable from s.

() Everything reachable is eventually marked visited: Suppose for contradiction some vertex u reachable from s is never visited. Take a shortest path . Let be the first vertex on this path that is never visited. Since is visited (by minimality of ), and explore(G, v_{i-1}) iterates over every edge out of , it must check whether is visited — and since it isn’t, explore recurses into it, marking it visited. This contradicts the assumption that is never visited.

Termination: Each vertex is marked visited at most once (the if not visited(u) guard prevents re-entering an already-visited vertex), so the recursion depth and total number of calls are both bounded by , and the algorithm terminates in finite time on a finite graph.

Note

This proof only establishes correctness for the connected component containing sexplore says nothing about vertices outside that component by design (see Drawbacks below).


Time & Space Complexity Analysis

General Case

Let be the connected component containing s (i.e. the set of vertices reachable from s), with vertices and edges.

ComplexityNotes
TimeEach reachable vertex is visited once; each of its outgoing edges is examined once
Space worst caseRecursion (call stack) depth can be as large as the component itself on a narrow/deep path

Note this is not over the whole graph — explore only touches the component reachable from s. To cover an entire (possibly disconnected) graph, you need the outer loop shown in Depth First Search (DFS), which restarts explore on every still-unvisited vertex.

Implementation-Dependent Variations

Data Structure ChoiceImpact on TimeImpact on SpaceNotes
Recursive (implicit stack) vs. explicit stackSame asymptoticallyRecursion adds call-stack overhead; risk of stack overflow on deep/skinny componentsThe pasted algorithm here is the recursive form
Adjacency list vs. matrix vs vs Matrix wastes time/space scanning non-edges
visited: boolean array vs. hash set either way either wayArray needs vertices indexable by small integers

Best / Worst / Average Case

  • Best case: s has no unvisited neighbors — beyond the initial call.
  • Worst case: Full connected component must be traversed — .
  • Average case: Same order as worst case; no probabilistic behavior to average over.

Drawbacks / Constraints

  • Only reaches one connected component. explore only reaches the set of vertices reachable from s — it will never touch vertices in a different connected component, even if they exist in the same graph object.
  • To cover a disconnected graph, you must restart explore on a vertex that has not yet been visited — this is exactly what the outer loop in Depth First Search (DFS) does.
  • Reachability only, by default. The base version only tells you whether a path exists (visited(u)), not what the path is — use the path-record version (prev, pre, post) if you need the actual route or timing structure.
  • Recursion depth risk. Since explore is naturally recursive, a very deep/narrow component can exhaust the call stack; an explicit-stack iterative rewrite avoids this.

Definition — Connected Undirected Graph An undirected graph is connected if for every pair of vertices in , there exists a path from to .


References / Links