Introduction to Graphs

Recall that a relation models a relationship between objects. Of particular note are binary relations which capture relationships between pairs of objects drawn from the same universe. For example, we might consider:

  • An ordering relationship between members of .
  • A friendship relationship between friends.
  • A connectedness relationship between cities by roads or available flights.
  • A transition relationship between states in an abstract machine. For example, an idealized traffic light is such an abstract machine where the traffic light switches between "green", "yellow", and "red."

Binary relationships are ubiquitous in mathematics and computer science, and they all have a similar structure: a relation . Can we exploit this structure to talk about all these sorts of relationships in a uniform manner? Is there a set of universal definitions and properties that apply to binary relations?

This is precisely the study of graph theory, the next area of discrete mathematics we'll examine in this course. Graph theory is really the study of binary relations, although we more commonly think of a graph as a visual object with nodes and edges.

Basic Definitions

Consider the following abstract binary relation over universe .

A graph allows us to visualize these relationships. Here is an example of a such graph for this relation:

A graph for relation R

We call the elements vertices or nodes of the graph. For each related pair of elements, we draw a line called an edge in our graph.

While our graph is simply a graphical representation of our binary relation, we traditionally represent a graph using a slightly different structure. We say that the graph above is . That is, graph is a pair of sets:

  • is the set of vertices in the graph. Here .
  • is the set of edges in the graph. Here .

Definition (Graph)

A graph is a pair of sets:

  • , the set of vertices or nodes of the graph.
  • , the set of edges of the graph.

Because we talk about edges so much, we frequently write the edge as , i.e., we drop the pair notation and simply write the vertices together.

Exercise (Sketchin')

Draw the graph where:

  • .
  • .

Variations

The fundamental definition of a graph is a simple riff on a binary relation. We call such graphs simple graphs. However, there exists several variations of graphs that accommodate the wide range of scenarios we might find ourselves in.

Directed versus Undirected Graphs

Because individual relationships are encoded as pairs, the order matters between vertices. For example, the pair is distinct from the pair . In a directed graph or digraph, we acknowledge this fact and distinguish between the two orderings.

For example, consider the following graph with

  • .
  • .

If we consider this graph directed, we would draw it as follows:

A directed graph

Note that the edges are directed edges where the direction is indicated by an arrowhead. If we were to have two vertices be mutually related, i.e., related in both directions, we need two edges, one for each direction. For example, and are mutually related, so we connect them with two edges and .

In contrast, we can consider to be undirected where we do not distinguish between the two orderings. Effectively, this means relations are unordered sets rather ordered pairs, but in terms of notation, we still keep . If we consider to be undirected, we would draw it as follows:

A undirected graph

Here, the edges are undirected, i.e., without arrowheads. Effectively, we treat a single edge pair as relating symmetrically by default, so the edge implies that is related to and is related to . Because of this, we should not include symmetric pairs in our set of edges. So we should define for the above graph as where we removed the symmetric pair .

When should we employ a directed versus undirected graph? We should employ a directed graph where it is not assumed that our relation is symmetric for every pair of related vertices. For example, a "loves"-style relationship where loves is not inherently symmetric since might not love . A directed graph allows us to represent this distinction. A directed graph can always represent an undirected graph by explicitly including symmetric edges. Therefore, we can think of an undirected graph as a shortcut where we can avoid writing extras edges if we know that our relation is already symmetric. For example, a "friends"-style relationship is symmetric because being friends with implies that is also 's friend.

Self-loops

Like symmetry, we may or may not take reflexivity of a relation for granted. If we do not take this for granted, i.e., some elements are reflexively related but not all of them are, then we might consider introducing self-loops into a graph. For example, consider the following digraph with .

A graph with self-loops

In this graph, and are related to themselves, but not .

Weights and Multi-graphs

Edges encode relations between objects in a graph. We can also carry additional information on these edges dependent on context. Most commonly, we will add numeric weights to our edges, e.g., to capture the distance between cities, or the cost of moving from one state to another. Both directed and undirected graphs can be weighted. As an example, consider the digraph with .

A weighted graph

We annotate the edges with a weight whose interpretation depends on context. For example, we can see that the edge has weight 5. We represent the weights on our graph formally with an additional structure, a function , that maps edges to weight value. The codomain of can be whatever type is appropriate for the problem at hand; here we choose integers (). For the above graph, we would define our weight function as:

We can also extend our graphs further by extending to be a multiset, a set that tracks duplicate elements. This allows us to express the idea of multiple edges, e.g., with different weights according to .

Simple Graphs Revisited

Now that we have introduced various variations on a graph, we can finally come back and formally define a simple graph as a graph with no such variations.

Definition (Simple Graph)

A simple graph is an undirected, unweighted graph with no self-loops.

In closing, we have many variations of a graph that we might consider. In successive readings, we'll consider various analyses over graphs and problems we might try to solve. The beauty of graph theory is that because graphs are so general, by defining and solving problems in terms of graphs, we can apply our solutions to a whole host of problems!

Exercise (What's That?, ‡)

Consider the following formal definition of an abstract graph with:

  1. Draw .
  2. Instantiate this abstract graph to a real-life scenario. Describe what objects the vertices represent and what relationship between objects is captured by .
  3. Observe that , , and are mutually connected in this graph, i.e., each vertex has an edge to the other. Interpret the fact that they are mutually connected in your real-life scenario. Is the fact that they are mutually connected have special meaning in the scenario you envisioned?

Trees

Frequently the relations we draw between objects are hierarchical in nature. That is the objects have a parent-to-child relationship, for example:

  • A literal parent and their children.
  • A manager and the employees that report to them.
  • A folder and the files it contains.

We represent these relationships with a specialized kind of graph called a tree.

Definition (Tree)

A tree is an undirected graph that contains no cycles.

Here is an artificial example of a tree with five nodes, --:

An example abstract tree with five nodes

We distinguish a vertex of the tree as its root. Here we'll consider to be the root of the tree although any of the vertices could be considered the root. By convention, we draw trees "upside down" with the root at the top and the tree growing downwards.

The root allows us to categorize the vertices of the tree by their distance from the root. We call a collection of vertices that are the same distance away from the root a level.

Definition (Level (Tree))

Let be a tree with a distinguished root . Define the th level of a tree, denoted to be the set of vertices that are nodes away from :

Definition (Height)

The height at tree is the maximum level of any of its vertices.

In our above example:

And the tree has height 2. Note that for any is since there are no nodes greater than 2 away from .

With levels defined, we can now formally define the parent-child relationship that characterizes trees:

Definition (Parent)

The parent of a vertex at level of a tree is the node for which the edge is in the tree and is at level .

Definition (Children)

The children of a vertex at level of a tree are the nodes for which each , the edge is in the tree and is at level .

Because a tree contains no cycles and the tree is rooted at a particular node, it follows that every vertex of a tree except the root has exactly one parent. (This is a worthwhile claim to prove yourself for practice!)

We can categorize trees by the maximal number of children any single node possesses. We call this value the tree's fan-out:

Definition (Fan-out)

The fan-out of a tree is the maximum number of children that any one vertex of the tree possesses. We call such a tree a -ary tree or a -tree for short. Notably a -tree is a sequence or a list, and a -tree is a binary tree.

Finally, we've restricted ourselves to connected trees, trees in which all its vertices are mutually reachable. If a graph is unconnected, but all of its connected components themselves are trees, then we call the graph a forest:

Definition (Connected Components)

Call an undirected graph connected if there exists a path between every pair of vertices in . A connected component of is a sub-graph of that is, itself, connected.

Definition (Forest)

A graph is a forest if all of its connected components are trees.

Directed Acyclic Graphs

We generally assume that a tree is an undirected graph. However, we can apply the same concepts to a directed graph. This results in a kind of graph called a directed acyclic graph (DAG):

Definition (Directed Acylic Graph)

A directed acyclic graph (DAG) is a directed graph that contains no cycles.

DAGs are outside the scope of our discussion of the basics of graphs, but be aware that DAGs have their own interesting properties and operations distinct from trees!

Depth-First Tree Traversals

Previously, we learned about depth-first and breadth-first traversals for graphs. Breadth-first traversals remain the same: we traverse the vertices of the tree by order of increasing level. However, the specialized nature of trees lets us specify different sorts of depth-first traversals, in particular, for binary trees where every node possesses at most two children. In such a tree, we call one child the left child and the other child the right child.

With this in mind, we can describe a recursive algorithm for depth-first search specialized to binary trees. In the Python-like code below, we use dot-notation to denote children, e.g., v.l for v's left child and v.r for v's right child.

def preDFS(u):
    visit(u)
    preDFS(u.l)
    preDFS(u.r)

Note that we visit the node u before visiting its children. Performing this traversal on our example tree from the beginning of this section yields the sequence:

This kind of depth-first traversal of the tree is called a pre-order traversal of the tree. We first visit the current element and then visit its children.

In contrast, a post-order traversal of the tree visits the children first and then the current node last.

def postDFS(u):
    postDFS(u.l)
    postDFS(u.r)
    visit(u)

A post-order traversal of the graph yields the following sequence:

Finally, we can intermix visiting children and visiting the current node with an in-order traversal:

def inDFS(u):
    inDFS(u.l)
    inDFS(u.r)
    visit(u)

An in-order traversal yields the following sequence: