diff options
| author | mo khan <mo.khan@gmail.com> | 2020-09-07 18:13:22 -0600 |
|---|---|---|
| committer | mo khan <mo.khan@gmail.com> | 2020-09-07 18:13:22 -0600 |
| commit | 78f5d8bc3b3f198d2ec72ebba803c381a26c5c76 (patch) | |
| tree | e2993510eca33392d761aa515c2c74dc618614e5 /doc | |
| parent | 4d6aa98bde0ce346053ee9b403449e3af53d269e (diff) | |
docs: add notes on graphs
Diffstat (limited to 'doc')
| -rw-r--r-- | doc/unit/12/README.md | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/doc/unit/12/README.md b/doc/unit/12/README.md index e69de29..66a4b6d 100644 --- a/doc/unit/12/README.md +++ b/doc/unit/12/README.md @@ -0,0 +1,225 @@ +# Graphs + +## Directed graph + +```plaintext +G = (V,E) where +* V is a set of vertices +* E is a set of ordered pairs of vertices called edges +``` + +An edge `(i, j)` is directed from `i` to `j`; + +* `i` is the source +* `j` is the target + +A `path` in `G` is a sequence of vertices. + +Typical operations: + +* `addEdge(i,j)`: Add the edge (i, j) to E. `O(1)` time. +* `removeEdge(i,j)`: Remove the edge `(i, j)` from E. `O(1)` time. +* `hasEdge(i, j)`: Check if the edge `(i, j)` is an element of E. `O(1)` time. +* `outEdges(i)`: Return a `List` of all ints `j` such that `(i,j)` is an element of E. `O(n)` time. +* `inEdges(i)`: Return a `List` of all ints `j` such that `(j,i)` is an element of E. `O(n)` time. + +`O(n^2)` space. + +### AdjacencyMatrix: Representing a Graph by a Matrix + +Is a way of representing an `n` vertex graph `G = (V,E)` +by an `n x m` matrix, `a`, whose entries are boolean values. + +```java +int n; +boolean[][] a; + +AdjacencyMatrix(int nO) { + n = nO; + a = new boolean[n][n]; +} +``` + +The matrix entry `a[i][j]` is defined as: + +```plaintext +a[i][j] = { true if (i, j) element of E otherwise false +``` + +```java +void addEdge(int i, int j) { + a[i][j] = true; +} + +void removeEdge(int i, int j) { + a[i][j] = false; +} + +boolean hasEdge(int i, int j) { + return a[i][j]; +} + +List<Integer> outEdges(int i) { + List<Integer> edges = new ArrayList<Integer>(); + for (int j = 0; j < n; j++) + if (a[i][j]) + edges.add(j); + return edges; +} + +List<Integer> inEdges(int i) { + List<Integer> edges = new ArrayList<Integer>(); + for (int j = 0; j < n; j++) + if (a[j][i]) + edges.add(j); + return edges; +} +``` + +It is large. It stores `n x n` boolean matrix, so it requires +at least `n^2` bits of memory. + +### AdjacencyLists: A Graph as a Collection of Lists + +representations of graphs take a more vertex-centric approach. +There are many possible implementations of adjacency lists. + +Operations: + +* `addEdge(i, j)`: `O(1)` time +* `removeEdge(i, j)`: `O(deg(1))` time +* `hasEdge(i, j)`: `O(deg(1))` time +* `outEdges(i)`: in `O(1)` time +* `inEdges(i)`: in `O(n + m)` time + +`O(n + m)` space. + + +```java +int n; +List<Integer>[] adj; + +AdjacencyLists(int nO) { + n = nO; + adj = (List<Integer>[])new List[n]; + for (int i = 0; i < n; i++) + adj[i] = new ArrayStack<Integer>(); +} + +void addEdge(int i, int j) { + adj[i].add(j); +} + +void removeEdge(int i, int j) { + Iterator<Integer> it = adj[i].iterator(); + while (it.hasNext()) { + if (it.next() == j) { + it.remove(); + return; + } + } +} + +boolean hasEdge(int i, int j) { + return adj[i].contains(j); +} + +List<Integer> outEdges(int i) { + return adj[i]; +} + +List<Integer> inEdges(int i) { + List<Integer> edges = new ArrayStack<Integer>(); + for (int j = 0; j < n; j++) + if (adj[j].contains(i)) + edges.add(j); + return edges; +} +``` + +## Graph Traversal + +### Breadth-First Search + +starts at a vertex `i` and visits, first the neighbours of `i`, +then the neighbours of the neighbours of `i`, then the +neighbours of the neighbours of the neighbours of `i`, and so on. + +It uses a `queue` and makes sure that the same vertex is +not added more than once. It does this be keep track of each +vertex that has been visited. + +```java +void bfs(Graph g, int r) { + boolean[] seen = new boolean[g.nVertices()]; + Queue<Integer> q = new SLList<Integer>(); + q.add(r); + seen[r] = true; + while (!q.isEmpty()) { + int i = q.remove(); + for (Integer j : g.outEdges(i)) { + if (!seen[j]) { + q.add(j); + seen[j] = true; + } + } + } +} +``` + +time complexity: when using an adjacency list `O(n+m)`. + +BFS is useful for computing shortest paths. + +### Depth-First Search + +is similar to the standard algorithm for traversing binary trees. +It fully explores one subtree before returning to the current +node and then exploring the other subtree. Another way to +think of depth-first search is by saying that it is similar +to breadth-first search except that it uses a stack instead +of a queue. + +Each node has a state: + +* not visited +* visited +* visiting + +Think of it as a recursive algorithm. + +```java +void dfs(Graph g, int r) { + byte[] c = new byte[g.nVertices()]; + dfs(g, r, c); +} + +// uses recursive stack +void dfs(Graph g, int i, byte[] c) { + c[i] = grey; + for (Integer j : g.outEdges(i)) { + if (c[j] == white) { + c[j] = grey; + dfs(g, j, c); + } + } + c[i] = black; +} + +void dfs2(Graph g, int r) { + byte[] c = new byte[g.nVertices()]; + Stack<Integer> s = new Stack<Integer>(); + s.push(r); + + while (!s.isEmpty()) { + int i = s.pop(); + if (c[i] == white) { + c[i] = grey; + for (int j : g.outEdges(i)) + s.push(j); + } + } +} +``` + +time complexity: when using an adjacency list `O(n+m)` time. |
