Graphs
A Graph
is a collection of Vertices
/Nodes
(denoted as ) and
Edges
(denoted as ) that connect pairs of vertices.
If the Edges
have a direction, then we have a Directed Graph
:
Otherwise, we have an Undirected Graph
:
For both graphs, the nodes are a
, b
, c
and d
.
However, the edges differ between the two.
In fact, if we group the edges for the single nodes,
we would have the following ones for the Directed
graph:
a -> {b, c}
b -> {d}
c -> {d}
d -> {}
And these for the Undirected
one:
a -> {b, c}
b -> {a, d}
c -> {a, d}
d -> {b, c}
So, we simply mapped the nodes with a list of so called Neighbors
.
Connected and Disconnected Graphs
The previous Graphs
were all Connected
,
since there was a path between each Node
.
However, we can also have Disconnected
ones:
In this case,
there is no connection between the nodes a
, b
and c
, d
.
Representation
The most common way to represent a Graph
is within an Adjacency List
,
which can be a Python
dictionary that maps the Node
to the set of Neighbors
.
Usually, a list of Edges
is provided,
where each element is either a list or a tuple of two elements.
For example:
edges = [
["a", "b"],
["a", "c"],
]
Adjacency List for a Directed Graph
Since the Graph
is Directed
,
we just need to consider a single dependency between two nodes (a single add
call).
from collections import defaultdict
edges = [
("a", "b"),
("a", "c"),
]
graph = defaultdict(list)
for a, b in edges:
graph[a].append(b)
Adjacency List for an Undirected Graph
For the Undirected
one,
we need a double dependency between the two nodes.
In fact, node a
has b
as Neighbor
, and vice versa.
from collections import defaultdict
edges = [
("a", "b"),
("a", "c"),
]
graph = defaultdict(list)
for a, b in edges:
graph[a].append(b)
graph[b].append(a) # the only difference compared to the other implementation