diff --git a/04. Trees and graphs/README.md b/04. Trees and graphs/README.md index b8cc240..5e9a892 100644 --- a/04. Trees and graphs/README.md +++ b/04. Trees and graphs/README.md @@ -225,3 +225,66 @@ The same graph algorithms that are used on adjacency lists (breadh-first search, * In the list representation, you can easily iterate through the neighbors of a node * In the matrix representation, you need to iterate through all the nodes to identify a node's neighbors + +## 6. Graph search + +The two most common ways to search a graph are depth-first search and breadth-first search. In DFS, we start at the root (or another arbitrarily selected node) and explore each branch completely before moving on to the next branch. We go deep first. + +In BFS, we start at the root (or another arbitrarily selected node) and explore each neighbor before going on to any of their children. We go wide. + + + +DFS is better if we want to visit every node in the graph, and BFS better if we want to find the (shortest) path between two nodes. + +### 6.1. Depth-first search (DFS) + +We visit a node `a` and then iterate through each of `a`'s neighbors. When visiting a node `b` that's a neighbor of `a`, we visit all of `b`'s neighbors before going on to `a`'s other neighbors. `a` exhaustively searches `b`'s branch before any of its other neighbors. + +We must check if a node has been visited, otherwise we might get stuck in an infinite loop. + +```java +void search(Node root) { + if (root == null) return; + visit(root); + root.visited = true; + foreach (Node n in root.adjacent) { + if (!n.visited) { + search(n); + } + } +} +``` + +### 6.2. Breadh-first search (BFS) + +There's a false assumption that BFS is recursive, it's not, it uses a queue. In BFS, node `a` visits each of `a`'s neighbors before visiting any of *their* neighbors. It's like searching level by level out from `a`. + +```java +void search(Node root) { + Queue queue = new Queue(); + root.marked = true; + queue.enqueue(root); // add to end of queue + + while (!queue.isEmpty()) { + Node r = queue.dequeue(); // remove from top of queue + visit(r); + foreach (Node n in r.adjacent) { + if (!n.marked) { + n.marked = true; + queue.enqueue(n); + } + } + } +} +``` + +### 6.3. Bidirectional search + +This is used to find the shortest path between a source and a destination node. It runs two simultaneous BFS, one from each node. When their searches collide, the path is found. + + + +Why is bidirectional search faster than BFS? Imagine that every node has <=`k` adjacent nodes and the shortest path from `s` to `t` has length `d`. + +* In BFS, we would search <=`k` nodes in the first level of the search, then <=`k` nodes for each of those `k`, so `k`2 nodes. We would do this `d` times, so O(kd) +* In bidirectional search, the two search collide at approximately d/2 levels, the midpoint. The search from `s` visits approximately kd/2 nodes, same as the search from `t`. So so O(kd/2) diff --git a/04. Trees and graphs/img/graph_search1.png b/04. Trees and graphs/img/graph_search1.png new file mode 100644 index 0000000..51f7e40 Binary files /dev/null and b/04. Trees and graphs/img/graph_search1.png differ diff --git a/04. Trees and graphs/img/graph_search2.png b/04. Trees and graphs/img/graph_search2.png new file mode 100644 index 0000000..8ea4fb0 Binary files /dev/null and b/04. Trees and graphs/img/graph_search2.png differ