En aquest tema, explorarem les diferents maneres de representar grafs en la programació. Els grafs són estructures de dades que consisteixen en nodes (o vèrtexs) i arestes que connecten aquests nodes. La representació adequada d'un graf és crucial per a l'eficiència dels algoritmes que operen sobre ell.
Tipus de Representació de Grafs
Hi ha diverses maneres de representar un graf, cadascuna amb els seus avantatges i inconvenients. Les representacions més comunes són:
- Matriu d'Adjacència
- Llista d'Adjacència
- Matriu d'Incidència
Matriu d'Adjacència
Una matriu d'adjacència és una matriu 2D de mida n x n on n és el nombre de nodes en el graf. Cada element A[i][j] de la matriu indica si hi ha una aresta entre el node i i el node j.
Avantatges:
- Accés ràpid per verificar si existeix una aresta entre dos nodes.
- Senzillesa en la implementació.
Inconvenients:
- Requereix
O(n^2)espai, la qual cosa pot ser ineficient per a grafs esparsos.
Exemple:
Considerem un graf amb 4 nodes (0, 1, 2, 3) i les següents arestes: (0-1), (0-2), (1-2), (2-3).
La matriu d'adjacència seria:
| 0 | 1 | 2 | 3 | |
|---|---|---|---|---|
| 0 | 0 | 1 | 1 | 0 |
| 1 | 1 | 0 | 1 | 0 |
| 2 | 1 | 1 | 0 | 1 |
| 3 | 0 | 0 | 1 | 0 |
Llista d'Adjacència
Una llista d'adjacència és una col·lecció de llistes. La llista a la posició i conté tots els nodes adjacents al node i.
Avantatges:
- Requereix menys espai per a grafs esparsos.
- Més eficient per iterar sobre els nodes adjacents.
Inconvenients:
- Accés més lent per verificar si existeix una aresta entre dos nodes comparat amb la matriu d'adjacència.
Exemple:
Considerem el mateix graf amb 4 nodes (0, 1, 2, 3) i les següents arestes: (0-1), (0-2), (1-2), (2-3).
La llista d'adjacència seria:
Matriu d'Incidència
Una matriu d'incidència és una matriu 2D de mida n x m on n és el nombre de nodes i m és el nombre d'arestes. Cada element B[i][j] indica si el node i està connectat per l'aresta j.
Avantatges:
- Pot ser útil per a certs tipus d'algoritmes que necessiten informació sobre les arestes.
Inconvenients:
- Requereix més espai que la llista d'adjacència per a grafs esparsos.
- Més complexa de gestionar.
Exemple:
Considerem el mateix graf amb 4 nodes (0, 1, 2, 3) i les següents arestes: (0-1), (0-2), (1-2), (2-3).
La matriu d'incidència seria:
| e1 | e2 | e3 | e4 | |
|---|---|---|---|---|
| 0 | 1 | 1 | 0 | 0 |
| 1 | 1 | 0 | 1 | 0 |
| 2 | 0 | 1 | 1 | 1 |
| 3 | 0 | 0 | 0 | 1 |
Implementació en Python
Matriu d'Adjacència
class GrafMatriuAdjacencia:
def __init__(self, nombre_nodes):
self.nombre_nodes = nombre_nodes
self.matriu = [[0] * nombre_nodes for _ in range(nombre_nodes)]
def afegir_aresta(self, u, v):
self.matriu[u][v] = 1
self.matriu[v][u] = 1 # Per a grafs no dirigits
def mostrar_matriu(self):
for fila in self.matriu:
print(fila)
# Exemple d'ús
graf = GrafMatriuAdjacencia(4)
graf.afegir_aresta(0, 1)
graf.afegir_aresta(0, 2)
graf.afegir_aresta(1, 2)
graf.afegir_aresta(2, 3)
graf.mostrar_matriu()Llista d'Adjacència
class GrafLlistaAdjacencia:
def __init__(self, nombre_nodes):
self.nombre_nodes = nombre_nodes
self.llista = [[] for _ in range(nombre_nodes)]
def afegir_aresta(self, u, v):
self.llista[u].append(v)
self.llista[v].append(u) # Per a grafs no dirigits
def mostrar_llista(self):
for i in range(self.nombre_nodes):
print(f"{i}: {self.llista[i]}")
# Exemple d'ús
graf = GrafLlistaAdjacencia(4)
graf.afegir_aresta(0, 1)
graf.afegir_aresta(0, 2)
graf.afegir_aresta(1, 2)
graf.afegir_aresta(2, 3)
graf.mostrar_llista()Matriu d'Incidència
class GrafMatriuIncidencia:
def __init__(self, nombre_nodes, nombre_arestes):
self.nombre_nodes = nombre_nodes
self.nombre_arestes = nombre_arestes
self.matriu = [[0] * nombre_arestes for _ in range(nombre_nodes)]
self.aresta_index = 0
def afegir_aresta(self, u, v):
if self.aresta_index < self.nombre_arestes:
self.matriu[u][self.aresta_index] = 1
self.matriu[v][self.aresta_index] = 1
self.aresta_index += 1
def mostrar_matriu(self):
for fila in self.matriu:
print(fila)
# Exemple d'ús
graf = GrafMatriuIncidencia(4, 4)
graf.afegir_aresta(0, 1)
graf.afegir_aresta(0, 2)
graf.afegir_aresta(1, 2)
graf.afegir_aresta(2, 3)
graf.mostrar_matriu()Exercicis Pràctics
- Implementació de Grafs Dirigits: Modifica les classes anteriors per suportar grafs dirigits.
- Conversió entre Representacions: Escriu funcions per convertir un graf representat com a matriu d'adjacència a una llista d'adjacència i viceversa.
- Càlcul del Grau dels Nodes: Implementa una funció que calculi el grau de cada node en un graf representat com a llista d'adjacència.
Resum
En aquesta secció, hem explorat les diferents maneres de representar grafs: matriu d'adjacència, llista d'adjacència i matriu d'incidència. Cada representació té els seus propis avantatges i inconvenients, i la selecció de la representació adequada depèn de les necessitats específiques de l'aplicació i dels algoritmes que s'utilitzaran. Hem proporcionat exemples de codi per a cada tipus de representació i suggerit exercicis pràctics per reforçar els conceptes apresos.
Curs d'Estructures de Dades
Mòdul 1: Introducció a les Estructures de Dades
- Què són les Estructures de Dades?
- Importància de les Estructures de Dades en la Programació
- Tipus d'Estructures de Dades
Mòdul 2: Llistes
- Introducció a les Llistes
- Llistes Enllaçades
- Llistes Doblement Enllaçades
- Llistes Circulars
- Exercicis amb Llistes
Mòdul 3: Piles
- Introducció a les Piles
- Operacions Bàsiques amb Piles
- Implementació de Piles
- Aplicacions de les Piles
- Exercicis amb Piles
Mòdul 4: Cues
- Introducció a les Cues
- Operacions Bàsiques amb Cues
- Cues Circulars
- Cues de Prioritat
- Exercicis amb Cues
Mòdul 5: Arbres
- Introducció als Arbres
- Arbres Binàries
- Arbres Binàries de Cerca
- Arbres AVL
- Arbres B
- Exercicis amb Arbres
Mòdul 6: Grafs
- Introducció als Grafs
- Representació de Grafs
- Algoritmes de Cerca en Grafs
- Algoritmes de Camins Mínims
- Aplicacions dels Grafs
- Exercicis amb Grafs
