Skillversitas

Graph Representation

There are several ways to represent a graph in a computer. The choice of representation affects the efficiency of operations.

1. Adjacency Matrix

A 2D matrix where matrix[i][j] = 1 if there is an edge from vertex i to j.

# Graph: A-B, A-C, B-D, C-D
vertices = ['A', 'B', 'C', 'D']
matrix = [
    [0, 1, 1, 0],  # A
    [1, 0, 0, 1],  # B
    [1, 0, 0, 1],  # C
    [0, 1, 1, 0],  # D
]

# Weighted
weighted_matrix = [
    [0, 4, 2, 0],
    [4, 0, 0, 3],
    [2, 0, 0, 5],
    [0, 3, 5, 0],
]

2. Adjacency List

A dictionary where the key is a vertex and the value is a list of neighbors.

# Graph: A-B, A-C, B-D, C-D
adj_list = {
    'A': ['B', 'C'],
    'B': ['A', 'D'],
    'C': ['A', 'D'],
    'D': ['B', 'C']
}

# Weighted
weighted_adj = {
    'A': [('B', 4), ('C', 2)],
    'B': [('A', 4), ('D', 3)],
    'C': [('A', 2), ('D', 5)],
    'D': [('B', 3), ('C', 5)]
}

3. Edge List

A list of all edges as vertex pairs.

# Graph: A-B, A-C, B-D, C-D
edges = [('A', 'B'), ('A', 'C'), ('B', 'D'), ('C', 'D')]

# Weighted
weighted_edges = [('A', 'B', 4), ('A', 'C', 2), ('B', 'D', 3), ('C', 'D', 5)]

Comparison

Aspect Adjacency Matrix Adjacency List Edge List
Space O(V²) O(V + E) O(E)
Check edge O(1) O(degree) O(E)
List neighbors O(V) O(degree) O(E)
Add edge O(1) O(1) O(1)
Remove edge O(1) O(degree) O(E)
Dense graph More efficient - -
Sparse graph - More efficient Efficient

Graph Class Implementation

class Graph:
    def __init__(self, directed=False):
        self.adj_list = {}
        self.directed = directed

    def add_vertex(self, v):
        if v not in self.adj_list:
            self.adj_list[v] = []

    def add_edge(self, v1, v2, weight=1):
        self.add_vertex(v1)
        self.add_vertex(v2)
        self.adj_list[v1].append((v2, weight))
        if not self.directed:
            self.adj_list[v2].append((v1, weight))

    def get_neighbors(self, v):
        return self.adj_list.get(v, [])

    def get_vertices(self):
        return list(self.adj_list.keys())
g = Graph()
g.add_edge('A', 'B', 4)
g.add_edge('A', 'C', 2)
g.add_edge('B', 'D', 3)

print(g.get_neighbors('A'))  # [('B', 4), ('C', 2)]

The adjacency list is the most common representation. Now let's study BFS for level-by-level graph traversal.