Skip to content

Commit

Permalink
graph exploration
Browse files Browse the repository at this point in the history
  • Loading branch information
emanuele-em committed Oct 24, 2023
1 parent b7f501a commit 8f83767
Show file tree
Hide file tree
Showing 4 changed files with 317 additions and 3 deletions.
6 changes: 3 additions & 3 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@
- [Basics of graphs](basic_of_graph.md)
- [ Graph terminology](graph_terminology.md)
- [ Graph representation](graph_representation.md)
<!-- - [Graph traversal](README.md) -->
<!-- - [ Depth-first search](README.md) -->
<!-- - [ Breadth-first search](README.md) -->
- [Graph traversal](graph_traversal.md)
- [ Depth-first search](depth_first_search.md)
- [ Breadth-first search](breadth_first_search.md)
<!-- - [ Applications](README.md) -->
<!-- - [Shortest paths](README.md) -->
<!-- - [Bellman–Ford algorithm](README.md) -->
Expand Down
145 changes: 145 additions & 0 deletions src/breadth_first_search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Breadth-first search

**Breadth-first search** (BFS) visits the nodes
in increasing order of their distance
from the starting node.
Thus, we can calculate the distance
from the starting node to all other
nodes using breadth-first search.
However, breadth-first search is more difficult
to implement than depth-first search.

Breadth-first search goes through the nodes
one level after another.
First the search explores the nodes whose
distance from the starting node is 1,
then the nodes whose distance is 2, and so on.
This process continues until all nodes
have been visited.

## Example

Let us consider how breadth-first search processes
the following graph:

<script type="text/tikz">
\begin{tikzpicture}
\node[draw, circle] (1) at (1,5) {1};
\node[draw, circle] (2) at (3,5) {2};
\node[draw, circle] (3) at (5,5) {3};
\node[draw, circle] (4) at (1,3) {4};
\node[draw, circle] (5) at (3,3) {5};
\node[draw, circle] (6) at (5,3) {6};

\path[draw,thick,-] (1) -- (2);
\path[draw,thick,-] (2) -- (3);
\path[draw,thick,-] (1) -- (4);
\path[draw,thick,-] (3) -- (6);
\path[draw,thick,-] (2) -- (5);
\path[draw,thick,-] (5) -- (6);
\end{tikzpicture}
</script>

Suppose that the search begins at node 1.
First, we process all nodes that can be reached
from node 1 using a single edge:

<script type="text/tikz">
\begin{tikzpicture}
\node[draw, circle,fill=lightgray] (1) at (1,5) {1};
\node[draw, circle,fill=lightgray] (2) at (3,5) {2};
\node[draw, circle] (3) at (5,5) {3};
\node[draw, circle,fill=lightgray] (4) at (1,3) {4};
\node[draw, circle] (5) at (3,3) {5};
\node[draw, circle] (6) at (5,3) {6};

\path[draw,thick,-] (1) -- (2);
\path[draw,thick,-] (2) -- (3);
\path[draw,thick,-] (1) -- (4);
\path[draw,thick,-] (3) -- (6);
\path[draw,thick,-] (2) -- (5);
\path[draw,thick,-] (5) -- (6);

\path[draw,thick,-] (1) -- (2);
\path[draw,thick,-] (2) -- (3);
\path[draw,thick,-] (1) -- (4);
\path[draw,thick,-] (2) -- (5);

\path[draw=red,thick,->,line width=2pt] (1) -- (2);
\path[draw=red,thick,->,line width=2pt] (1) -- (4);
\end{tikzpicture}
</script>

After this, we proceed to nodes 3 and 5:

<script type="text/tikz">
\begin{tikzpicture}
\node[draw, circle,fill=lightgray] (1) at (1,5) {1};
\node[draw, circle,fill=lightgray] (2) at (3,5) {2};
\node[draw, circle,fill=lightgray] (3) at (5,5) {3};
\node[draw, circle,fill=lightgray] (4) at (1,3) {4};
\node[draw, circle,fill=lightgray] (5) at (3,3) {5};
\node[draw, circle] (6) at (5,3) {6};

\path[draw,thick,-] (1) -- (2);
\path[draw,thick,-] (2) -- (3);
\path[draw,thick,-] (1) -- (4);
\path[draw,thick,-] (3) -- (6);
\path[draw,thick,-] (2) -- (5);
\path[draw,thick,-] (5) -- (6);

\path[draw,thick,-] (1) -- (2);
\path[draw,thick,-] (2) -- (3);
\path[draw,thick,-] (1) -- (4);
\path[draw,thick,-] (2) -- (5);

\path[draw=red,thick,->,line width=2pt] (2) -- (3);
\path[draw=red,thick,->,line width=2pt] (2) -- (5);
\end{tikzpicture}
</script>

Finally, we visit node 6:

<script type="text/tikz">
\begin{tikzpicture}
\node[draw, circle,fill=lightgray] (1) at (1,5) {1};
\node[draw, circle,fill=lightgray] (2) at (3,5) {2};
\node[draw, circle,fill=lightgray] (3) at (5,5) {3};
\node[draw, circle,fill=lightgray] (4) at (1,3) {4};
\node[draw, circle,fill=lightgray] (5) at (3,3) {5};
\node[draw, circle,fill=lightgray] (6) at (5,3) {6};

\path[draw,thick,-] (1) -- (2);
\path[draw,thick,-] (2) -- (3);
\path[draw,thick,-] (1) -- (4);
\path[draw,thick,-] (3) -- (6);
\path[draw,thick,-] (2) -- (5);
\path[draw,thick,-] (5) -- (6);

\path[draw,thick,-] (1) -- (2);
\path[draw,thick,-] (2) -- (3);
\path[draw,thick,-] (1) -- (4);
\path[draw,thick,-] (2) -- (5);

\path[draw=red,thick,->,line width=2pt] (3) -- (6);
\path[draw=red,thick,->,line width=2pt] (5) -- (6);
\end{tikzpicture}
</script>

Now we have calculated the distances
from the starting node to all nodes of the graph.
The distances are as follows:

| node | distance |
| --- | --- |
| 1 | 0 |
| 2 | 1 |
| 3 | 2 |
| 4 | 1 |
| 5 | 2 |
| 6 | 3 |

Like in depth-first search,
the time complexity of breadth-first search
is $O(n+m)$, where $n$ is the number of nodes
and $m$ is the number of edges.
158 changes: 158 additions & 0 deletions src/depth_first_search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# Depth-first search

**Depth-first search** (DFS)
is a straightforward graph traversal technique.
The algorithm begins at a starting node,
and proceeds to all other nodes that are
reachable from the starting node using
the edges of the graph.

Depth-first search always follows a single
path in the graph as long as it finds
new nodes.
After this, it returns to previous
nodes and begins to explore other parts of the graph.
The algorithm keeps track of visited nodes,
so that it processes each node only once.

## Example

Let us consider how depth-first search processes
the following graph:

<script type="text/tikz">
\begin{tikzpicture}
\node[draw, circle] (1) at (1,5) {1};
\node[draw, circle] (2) at (3,5) {2};
\node[draw, circle] (3) at (5,4) {3};
\node[draw, circle] (4) at (1,3) {4};
\node[draw, circle] (5) at (3,3) {5};

\path[draw,thick,-] (1) -- (2);
\path[draw,thick,-] (2) -- (3);
\path[draw,thick,-] (1) -- (4);
\path[draw,thick,-] (3) -- (5);
\path[draw,thick,-] (2) -- (5);
\end{tikzpicture}
</script>

We may begin the search at any node of the graph;
now we will begin the search at node 1.

The search first proceeds to node 2:


<script type="text/tikz">
\begin{tikzpicture}
\node[draw, circle,fill=lightgray] (1) at (1,5) {1};
\node[draw, circle,fill=lightgray] (2) at (3,5) {2};
\node[draw, circle] (3) at (5,4) {3};
\node[draw, circle] (4) at (1,3) {4};
\node[draw, circle] (5) at (3,3) {5};

\path[draw,thick,-] (1) -- (2);
\path[draw,thick,-] (2) -- (3);
\path[draw,thick,-] (1) -- (4);
\path[draw,thick,-] (3) -- (5);
\path[draw,thick,-] (2) -- (5);

\path[draw=red,thick,->,line width=2pt] (1) -- (2);
\end{tikzpicture}
</script>

After this, nodes 3 and 5 will be visited:

<script type="text/tikz">
\begin{tikzpicture}
\node[draw, circle,fill=lightgray] (1) at (1,5) {1};
\node[draw, circle,fill=lightgray] (2) at (3,5) {2};
\node[draw, circle,fill=lightgray] (3) at (5,4) {3};
\node[draw, circle] (4) at (1,3) {4};
\node[draw, circle,fill=lightgray] (5) at (3,3) {5};

\path[draw,thick,-] (1) -- (2);
\path[draw,thick,-] (2) -- (3);
\path[draw,thick,-] (1) -- (4);
\path[draw,thick,-] (3) -- (5);
\path[draw,thick,-] (2) -- (5);

\path[draw=red,thick,->,line width=2pt] (1) -- (2);
\path[draw=red,thick,->,line width=2pt] (2) -- (3);
\path[draw=red,thick,->,line width=2pt] (3) -- (5);
\end{tikzpicture}
</script>

The neighbors of node 5 are 2 and 3,
but the search has already visited both of them,
so it is time to return to the previous nodes.
Also the neighbors of nodes 3 and 2
have been visited, so we next move
from node 1 to node 4:

<script type="text/tikz">
\begin{tikzpicture}
\node[draw, circle,fill=lightgray] (1) at (1,5) {1};
\node[draw, circle,fill=lightgray] (2) at (3,5) {2};
\node[draw, circle,fill=lightgray] (3) at (5,4) {3};
\node[draw, circle,fill=lightgray] (4) at (1,3) {4};
\node[draw, circle,fill=lightgray] (5) at (3,3) {5};

\path[draw,thick,-] (1) -- (2);
\path[draw,thick,-] (2) -- (3);
\path[draw,thick,-] (1) -- (4);
\path[draw,thick,-] (3) -- (5);
\path[draw,thick,-] (2) -- (5);

\path[draw=red,thick,->,line width=2pt] (1) -- (4);
\end{tikzpicture}
</script>

After this, the search terminates because it has visited
all nodes.

The time complexity of depth-first search is $O(n+m)$
where $n$ is the number of nodes and $m$ is the
number of edges,
because the algorithm processes each node and edge once.

## Implementation

Depth-first search can be conveniently
implemented using recursion.
The following function _dfs_ begins
a depth-first search at a given node.
The function assumes that the graph is
stored as adjacency lists in an array

```rust
# const N:usize = 10;
let mut adj: [Vec<i32>; N]= Default::default();
# println!("{adj:?}");
```

and also maintains an array

```rust
let mut visited: Vec<bool> = Vec::new();
# println!("{visited:?}");
```

that keeps track of the visited nodes.
Initially, each array value is `false`,
and when the search arrives at node $s$,
the value of `visited[s]` becomes `true`.
The function can be implemented as follows:

```rust
# const N:usize = 10;
# let mut adj: [Vec<i32>; N]= Default::default();
# let mut visited: Vec<bool> = Vec::new();
fn dfs(s: usize, adj: &[Vec<i32>],visited: &mut Vec<bool>){
if visited[s] {return}
visited[s] = true;
// process node s
for &u in &adj[s] {
dfs(u as usize, adj, visited);
}
}
```
11 changes: 11 additions & 0 deletions src/graph_traversal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Graph traversal

This chapter discusses two fundamental
graph algorithms:
depth-first search and breadth-first search.
Both algorithms are given a starting
node in the graph,
and they visit all nodes that can be reached
from the starting node.
The difference in the algorithms is the order
in which they visit the nodes.

0 comments on commit 8f83767

Please sign in to comment.