Graphs

Let’s break down how to make and use graphs — the building blocks of networks.structure

What is a Graph?

A graph is a way to show how things (called nodes) are connected to each other through relationships (called edges). You can also store extra information about each node, edge, or even the whole graph to describe them better. Graphs are very flexible and can represent many kinds of real-world connections. Don’t worry if this sounds abstract — we’ll look at clear examples in the next section.

You’ve probably seen graphs before in things like social networks. But graphs are much more powerful and can represent many kinds of data. For example, even images and text — which might not seem like graphs at first — can be modeled this way. By looking at them as graphs, we can discover patterns and structures that aren’t obvious, and build an intuition for understanding other, less regular types of graph data.

What does a Graph looks like?

One cool way to see how a graph’s nodes are connected is with something called an adjacency matrix. Here, we’ve taken a tiny 4×4 image (just 16 pixels) and shown how the nodes (pixels) link up in a grid. Each cell in the matrix tells you if two nodes are connected. The three views below — the grid, the matrix, and the graph — are just different ways of looking at the same data.

Image Pixels
Adjacency Matrix
Graph

How to create a graph data structure?

Okay, let’s get hands-on. Building a graph is pretty straightforward — it’s just about figuring out how to store nodes and edges in data structures.

We’ll walk through this step by step:

Storing Nodes

In most cases, we don’t need a fancy structure for nodes. You can just store them in a list or set. For example:

# Define our nodes
nodes = ["A", "B", "C", "D"]
print("Nodes:", nodes)

Representing Connections (Adjacency Matrix)

Once you’ve got nodes, you need to show which ones are connected.

An adjacency matrix is like a big grid. Each row and column represents a node. If two nodes are connected, we put 1; otherwise, 0.

# Create adjacency matrix for 4 nodes
# A -- B
# |    |
# C -- D
adj_matrix = [
    [0, 1, 1, 0],  # Connections for A
    [1, 0, 0, 1],  # Connections for B
    [1, 0, 0, 1],  # Connections for C
    [0, 1, 1, 0],  # Connections for D
]

This matrix says:

Connections:

Traversing the Graph (Visiting Nodes)

Now let’s say you want to walk through your graph — maybe to find all nodes or paths. Two popular ways are:

🕸️ Depth-First Search (DFS)

Think of it like exploring as far as possible down one path before backtracking.

def dfs(node, visited):
    if node not in visited:
        print("Visiting:", node)
        visited.add(node)
        for neighbor, connected in enumerate(adj_matrix[node]):
            if connected:
                dfs(neighbor, visited)

visited = set()
dfs(0, visited)  # Start at node 0 (A)

🌊 Breadth-First Search (BFS)

This one explores level by level — like ripples in water.

def bfs(start):
    visited = set()
    queue = deque([start])

    while queue:
        node = queue.popleft()
        if node not in visited:
            print("Visiting:", node)
            visited.add(node)
            for neighbor, connected in enumerate(adj_matrix[node]):
                if connected and neighbor not in visited:
                    queue.append(neighbor)

bfs(0)  # Start at node 0 (A)

With this basic setup, you can start doing cool stuff like finding paths, checking if your graph is connected, or even visualizing it.