Graphs
Breadth-First Search
From a start vertex, explore the graph layer by layer. Use a queue and a "visited" set. Dequeue a vertex, visit it, enqueue all unvisited neighbours.
Algorithm
Canonical adjacency list:
1 -> [2, 3]
2 -> [1, 4]
3 -> [1, 4]
4 -> [2, 3, 5]
5 -> [4, 6]
6 -> [5]
Starting at vertex 1, the BFS visit order is [1, 2, 3, 4, 5, 6].
Basic Implementation
basic.R
adj <- list()
adj[["1"]] <- c(2, 3)
adj[["2"]] <- c(1, 4)
adj[["3"]] <- c(1, 4)
adj[["4"]] <- c(2, 3, 5)
adj[["5"]] <- c(4, 6)
adj[["6"]] <- c(5)
start <- 1
visited <- list()
visited[[as.character(start)]] <- TRUE
queue <- c(start)
order <- integer(0)
head <- 1
while (head <= length(queue)) {
v <- queue[head]
head <- head + 1
order[length(order) + 1] <- v
neighbours <- adj[[as.character(v)]]
i <- 1
while (i <= length(neighbours)) {
nb <- neighbours[i]
if (is.null(visited[[as.character(nb)]])) {
visited[[as.character(nb)]] <- TRUE
queue[length(queue) + 1] <- nb
}
i <- i + 1
}
}
cat("[", paste(order, collapse = ", "), "]\n", sep = "")
Complexity
- Time: O(V + E)
- Space: O(V)
Implementation notes
- R:
adjis a named list keyed byas.character(vertex)with integer neighbour vectors. The lesson keeps the queue as a vector plus aheadcursor rather than reaching forqueue <- queue[-1], so the enqueue / dequeue moves stay explicit and avoid the O(n) reshuffle that negative-index slicing would impose every step. - A
visitednamed list is the explicit "visited" set keyed byas.character(vertex)(is.null(visited[[as.character(nb)]])checks absence); the queue grows viaqueue[length(queue) + 1] <- nbto keep the append visible. - The replay prints the dequeued vertex, the queue, the visited set, and the running visit order each frame.
queue
A plain `queue <- c(start)` integer vector with an integer `head` cursor implements FIFO without hiding the iteration shape.
visited-before-enqueue
Mark a vertex visited before pushing it onto the queue. Keeps the queue size bounded by V.