Depth-First Search (DFS) is a popular algorithm used to explore graphs and trees in a systematic way. It starts from a node and explores as far as possible along each branch before backtracking. This approach is useful in many scenarios, such as finding paths in a maze, checking connectivity in networks, and analyzing relationships in social networks or databases. For beginners learning R, implementing DFS is a great way to understand recursion, stacks, and graph traversal logic.
Unlike simpler searches, DFS dives deep into each path before moving to the next one, making it efficient for problems where the solution is likely to be far from the starting point. Understanding DFS also provides a foundation for other algorithms, like topological sorting, cycle detection, and solving puzzles programmatically. Practicing DFS helps beginners strengthen their problem-solving skills and grasp fundamental computer science concepts.
Program 1: Depth-First Search using recursion
This program demonstrates a basic DFS implementation for a graph using recursion.
dfs_recursive <- function(graph, node, visited = c()) {
visited <- c(visited, node)
cat(node, " ")
for (neighbor in graph[[node]]) {
if (!(neighbor %in% visited)) {
visited <- dfs_recursive(graph, neighbor, visited)
}
}
return(visited)
}
graph <- list(
"A" = c("B", "C"),
"B" = c("D", "E"),
"C" = c("F"),
"D" = c(),
"E" = c(),
"F" = c()
)
dfs_recursive(graph, "A")This program works by visiting a node, marking it as visited, and recursively visiting all its neighbors. Beginners can understand recursion better by seeing how DFS explores one path fully before backtracking.
Program 2: Depth-First Search using a stack
Instead of recursion, DFS can be implemented using a stack to manage nodes manually. This method avoids potential stack overflow for very large graphs.
dfs_stack <- function(graph, start) {
visited <- c()
stack <- c(start)
while (length(stack) > 0) {
node <- tail(stack, 1)
stack <- head(stack, -1)
if (!(node %in% visited)) {
visited <- c(visited, node)
cat(node, " ")
stack <- c(stack, rev(graph[[node]]))
}
}
return(visited)
}
graph <- list(
"A" = c("B", "C"),
"B" = c("D", "E"),
"C" = c("F"),
"D" = c(),
"E" = c(),
"F" = c()
)
dfs_stack(graph, "A")Here, nodes are pushed onto a stack, and the last node is visited first. This iterative approach helps beginners understand the underlying mechanism of recursion and stack behavior in DFS.
Program 3: DFS with a different starting node
This example shows that DFS can start from any node, not just the first one. It is useful when exploring disconnected graphs.
dfs_recursive <- function(graph, node, visited = c()) {
visited <- c(visited, node)
cat(node, " ")
for (neighbor in graph[[node]]) {
if (!(neighbor %in% visited)) {
visited <- dfs_recursive(graph, neighbor, visited)
}
}
return(visited)
}
graph <- list(
"A" = c("B", "C"),
"B" = c("D", "E"),
"C" = c("F"),
"D" = c(),
"E" = c(),
"F" = c()
)
dfs_recursive(graph, "C")Starting from a different node changes the traversal order but the logic remains the same. Beginners can see how DFS adapts to different starting points in a graph.
Program 4: DFS for a graph with cycles
DFS works with cyclic graphs too, as long as we track visited nodes to prevent infinite loops.
dfs_recursive <- function(graph, node, visited = c()) {
visited <- c(visited, node)
cat(node, " ")
for (neighbor in graph[[node]]) {
if (!(neighbor %in% visited)) {
visited <- dfs_recursive(graph, neighbor, visited)
}
}
return(visited)
}
cyclic_graph <- list(
"A" = c("B"),
"B" = c("C"),
"C" = c("A", "D"),
"D" = c()
)
dfs_recursive(cyclic_graph, "A")This version teaches beginners the importance of marking visited nodes to handle cycles safely.
Program 5: DFS to record traversal order
Sometimes we need to store the traversal order for further analysis, such as topological sorting or path finding.
dfs_order <- function(graph, node, visited = c(), order = c()) {
visited <- c(visited, node)
order <- c(order, node)
for (neighbor in graph[[node]]) {
if (!(neighbor %in% visited)) {
result <- dfs_order(graph, neighbor, visited, order)
visited <- result$visited
order <- result$order
}
}
return(list(visited = visited, order = order))
}
graph <- list(
"A" = c("B", "C"),
"B" = c("D", "E"),
"C" = c("F"),
"D" = c(),
"E" = c(),
"F" = c()
)
result <- dfs_order(graph, "A")
cat("Traversal order:", result$order)This approach is useful for beginners who want to see how DFS can be adapted for practical applications beyond just visiting nodes.
Frequently Asked Questions (FAQ)
DFS is often confusing for beginners, so here are some common questions answered.
Q1. Can DFS work on disconnected graphs?
Yes, but you need to start DFS from each unvisited node to cover the entire graph.
Q2. What is the difference between DFS and BFS?
DFS explores as far as possible along one branch before backtracking, while BFS explores neighbors level by level.
Q3. Can DFS handle cycles?
Yes, if visited nodes are tracked to prevent infinite loops.
Q4. When should I use DFS over BFS?
DFS is useful when you want to explore deep paths or need to find a solution far from the start node.
Conclusion
Depth-First Search is a versatile algorithm that allows exploration of graphs and trees efficiently. Beginners can implement DFS using recursion or a stack, handle cycles safely, and record traversal orders for further analysis.
Practicing DFS in R helps strengthen understanding of recursion, stacks, and graph theory. It provides a solid foundation for advanced algorithms and practical applications like maze solving, pathfinding, and network analysis. Exploring DFS in different ways builds problem-solving skills and deepens comprehension of algorithm design.




