Introducción

En este tema, aprenderemos sobre las diferentes formas de representar grafos en estructuras de datos. La representación adecuada de un grafo es crucial para la eficiencia de los algoritmos que operan sobre él. Exploraremos las dos representaciones más comunes: la matriz de adyacencia y la lista de adyacencia.

Conceptos Básicos

Antes de profundizar en las representaciones, repasemos algunos conceptos básicos sobre grafos:

  • Grafo (G): Un conjunto de vértices (nodos) y aristas (enlaces) que conectan pares de vértices.
  • Vértice (V): Un nodo en el grafo.
  • Arista (E): Un enlace entre dos vértices.
  • Grafo dirigido: Las aristas tienen una dirección, es decir, van de un vértice a otro.
  • Grafo no dirigido: Las aristas no tienen dirección, es decir, la conexión entre los vértices es bidireccional.
  • Peso: Un valor asociado a una arista, común en grafos ponderados.

Representaciones de Grafos

  1. Matriz de Adyacencia

Una matriz de adyacencia es una matriz cuadrada utilizada para representar un grafo. Los elementos de la matriz indican si pares de vértices están adyacentes o no en el grafo.

Características

  • Dimensiones: n x n, donde n es el número de vértices.
  • Elementos:
    • En un grafo no ponderado, los elementos son 0 o 1.
    • En un grafo ponderado, los elementos son los pesos de las aristas.

Ejemplo

Consideremos un grafo no dirigido con 4 vértices (A, B, C, D) y las siguientes aristas: (A-B), (A-C), (B-D), (C-D).

La matriz de adyacencia sería:

A B C D
A 0 1 1 0
B 1 0 0 1
C 1 0 0 1
D 0 1 1 0

Implementación en Python

# Crear una matriz de adyacencia para un grafo no dirigido
def create_adjacency_matrix(n, edges):
    matrix = [[0] * n for _ in range(n)]
    for edge in edges:
        u, v = edge
        matrix[u][v] = 1
        matrix[v][u] = 1  # Para grafos no dirigidos
    return matrix

# Ejemplo de uso
n = 4  # Número de vértices
edges = [(0, 1), (0, 2), (1, 3), (2, 3)]  # Aristas
adj_matrix = create_adjacency_matrix(n, edges)
for row in adj_matrix:
    print(row)

  1. Lista de Adyacencia

Una lista de adyacencia es una colección de listas, una por cada vértice, donde cada lista contiene los vértices adyacentes a ese vértice.

Características

  • Estructura: Un array de listas.
  • Espacio: Más eficiente en términos de espacio para grafos dispersos (sparse graphs).

Ejemplo

Usando el mismo grafo anterior, la lista de adyacencia sería:

A: [B, C]
B: [A, D]
C: [A, D]
D: [B, C]

Implementación en Python

# Crear una lista de adyacencia para un grafo no dirigido
def create_adjacency_list(n, edges):
    adj_list = [[] for _ in range(n)]
    for edge in edges:
        u, v = edge
        adj_list[u].append(v)
        adj_list[v].append(u)  # Para grafos no dirigidos
    return adj_list

# Ejemplo de uso
n = 4  # Número de vértices
edges = [(0, 1), (0, 2), (1, 3), (2, 3)]  # Aristas
adj_list = create_adjacency_list(n, edges)
for i, neighbors in enumerate(adj_list):
    print(f"{i}: {neighbors}")

Comparación de Representaciones

Característica Matriz de Adyacencia Lista de Adyacencia
Espacio O(n^2) O(n + m)
Acceso a aristas O(1) O(k)
Iteración sobre vecinos O(n) O(k)
Mejor para Grafos densos Grafos dispersos

Ejercicio Práctico

Ejercicio 1: Crear una Matriz de Adyacencia

Dado un grafo dirigido con 5 vértices y las siguientes aristas: (0-1), (0-2), (1-3), (2-3), (3-4), crea la matriz de adyacencia.

Solución

def create_adjacency_matrix_directed(n, edges):
    matrix = [[0] * n for _ in range(n)]
    for edge in edges:
        u, v = edge
        matrix[u][v] = 1
    return matrix

# Ejemplo de uso
n = 5  # Número de vértices
edges = [(0, 1), (0, 2), (1, 3), (2, 3), (3, 4)]  # Aristas
adj_matrix = create_adjacency_matrix_directed(n, edges)
for row in adj_matrix:
    print(row)

Ejercicio 2: Crear una Lista de Adyacencia

Dado un grafo no dirigido con 5 vértices y las siguientes aristas: (0-1), (0-2), (1-3), (2-3), (3-4), crea la lista de adyacencia.

Solución

def create_adjacency_list_undirected(n, edges):
    adj_list = [[] for _ in range(n)]
    for edge in edges:
        u, v = edge
        adj_list[u].append(v)
        adj_list[v].append(u)
    return adj_list

# Ejemplo de uso
n = 5  # Número de vértices
edges = [(0, 1), (0, 2), (1, 3), (2, 3), (3, 4)]  # Aristas
adj_list = create_adjacency_list_undirected(n, edges)
for i, neighbors in enumerate(adj_list):
    print(f"{i}: {neighbors}")

Conclusión

En esta sección, hemos aprendido sobre las dos representaciones más comunes de grafos: la matriz de adyacencia y la lista de adyacencia. Cada representación tiene sus propias ventajas y desventajas, y la elección de una sobre la otra depende de las características del grafo y de los algoritmos que se vayan a utilizar. En el próximo tema, exploraremos las técnicas de búsqueda en grafos, como BFS y DFS, que se basan en estas representaciones.

© Copyright 2024. Todos los derechos reservados