Graphs Intro
Author: Josh Hug

Overview

Terminology.

Interesting Graph Problems.

Graph Representation. There are many possible internal representations of a graph. We discussed three. You should be able to determine the runtime tradeoffs for each.

Usually, we use the adjacency-lists representation because most real-world graphs are sparse.

Depth First Traversal. Much like we can traverse trees, we can also traverse graphs. The most natural traversal is the so called depth first traversal, represented by the following pseudocode:

dfs(s):
    mark s
    for each unmarked neighbor X of s:
        dfs(x)

The result is that we explore the entirety of each adjacent subgraph before moving on to the next subgraph. DFS is the same thing as our depth first traversals for trees (a.k.a. preorder, inorder, and postorder). In the next lecture we'll differentiate DFS preorder vs. DFS postorder.

Paths: A Case Study. We use the Paths problem to showcase two things: decoupling and the power of DFS.

By decoupling, I mean the fact that graph algorithms are not usually included inside a Graph class itself. This is because there are just too many such algorithms that are interesting, which result in a very bloated Graph class. Instead, we usually create an object whose constructor takes a Graph object, and it does all the processing at construction time.

In the Paths problem, we create a class that supports hasPathTo() in constant time and pathTo() in time proportional to the length of the path.

We create a solution class DepthFirstPaths whose constructor is just DFS as described above, but where we also set the edgeTo for each vertex before we visit it. We did not discuss how to write hasPathTo() or pathTo(), but it should be clear how we'd achieve this goal.

Throughout these problems, we define V as the number of vertices in a graph, and E as the number of edges.

C level

See lec35.

B level

  1. Why is the runtime of DFS O(V + E) time if we use an adjacency list?
  2. What is the runtime of DFS if we use an adjacency matrix? Give the tightest big-O bound you can.
  3. Adapted from Algorithm 4.10: Prove that every connected graph has a vertex whose removal (including all adjacent edges) will not disconnect the graph, and create a DFS based algorithm that finds such a vertex.

A level

  1. Just for fun: Prove that a graph is two-colorable (bipartite) if and only if it contains no odd-length cycle.