- Arista: relación entre nodos en la que existe un orden (grafo dirigido: -⇒, ⇐-)
- Arco: relación entre nodos en la que no existe un orden (grafo no dirigido: ---)
¿Qué es un grafo?
- Un grafo es un modelo matemático que permite representar relaciones arbitrarias entre objetos.
Tipos de grafos
Definición formal
Conceptos básicos
- Bucle: Arco u arista con igual origen que destino.
- Grado de un nodo: Número de arcos u aristas conectados al nodo.
- Grado de Entrada (gE) de un nodo: Número de arcos o aristas que tienen al nodo como destino
- Grado de Salida (gS) de un nodo: Número de arcos o aristas que tienen al nodo como origen.
- V3 es un nodo fuente (nodo que se conecta con todo el mundo)
- V4 es un nodo sumidero (nodo que no se conecta con nadie pero que es accesible para todo el mundo)
- V5 es u nodo aislado (ningún grado de entrada ni ninguno de salida)
Capacidad de un grafo
- n = número de nodos de un grafo
- Número mínimo de arcos en un grafo = 0 (todos aislados)
- Número máximo de arcos en un grafo = n^2 (todos conectados con todos (con bucles))
Representación en memoria
Densidad de un grafo
Clase Grafo (Matriz de adyacencias)
- Hay que almacenar los nodos (de cualquier tipo), las aristas y los pesos
Matrices adyacencias | Listas adyacencias |
---|---|
- Usan memoria estática ![]() | - Usan memoria dinámica |
Análisis de eficiencia
Listas de adyacencia
Análisis de Eficiencia
Clase Grafo. Métodos básicos
Matriz de adyacencia
- Complejidad 0(1)
getNode()
- Complejidad O(n)
public int getNode (T node)
{
for (int i=0; i<size; i++)
if (nodes[i].equals(node))
return (i); // returns the node’s position
return (-1); // search fails, node does not exist
}
addNode()
- Complejidad O(n)
public void addNode (T node)
{
// precondition: node does not exits and there is
// available space for the node.
if (getNode(node)== -1 && size<nodes.length)
{
nodes[size] = node;
//inserts void edges
for (int i=0; i<=size; i++)
{
edges[size][i]=false;
edges[i][size]=false;
weight[size][i]=0;
weight[i][size]=0;
}
++size;
}
}
removeNode()
- Complejidad O(n)
public void removeNode (T node){
int i = getNode(node);
if (i>=0) {
--size;
if (i != size+1) { // it is not the last node
nodes[i] = nodes[size]; //replaces by the last node
//replace elements in the vectors edges and weights
for (int j=0; j<=size; j++) {
edges[j][i]=edges[j][size];
edges[i][j]=edges[size][j];
weight[i][j]=weight[size][j];
weight[j][i]=weight[j][size];
}
// loop (diagonal)
edges[i][i] = edges[size][size];
weight[i][i] = weight[size][size];
}
}
existsEdge()
- Complejidad O(n)
public boolean existsEdge (T origin, T destination)
{
int i=getNode(origin);
int j=getNode(destination);
// precondition: both nodes must exist. // if don’t... should we throw an exception?
if (i>=0 && j>=0)
return(edges[i][j]);
else
return (false);
}
addEdge()
- Complejidad O(n)
public void addEdge (T origin, T destination, double
edgeWeight)
{
// precondition: the edge must not already exist.
if (!existEdge(origin, destination))
{
int i=getNode(origin);
int j=getNode(destination);
edges[i][j]=true;
weight[i][j]=edgeWeight;
}
else
; // what about throwing an exception here?
}
removeEdge()
- Complejidad O(n)
public void removeEdge (T origin, T destination){
// precondition: the edge must exist.
if (existsEdge(origin, destination)) {
int i=getNode(origin);
int j=getNode(destination);
edges[i][j]=false;
weight[i][j]=0.0;
}
else
; // what about throwing an exception?
}
print()
- Complejidad O(n^2)
public void print(){
for (int k=0; k<size; k++)
nodes[k].print();
for (int i=0; i<size; i++) {
for (int j=0; j<size; j++) {
System.out.print(edges[i][j] + “(“);
System.out.print(weight[i][j] + “) “);
}
System.out.println();
}
Más conceptos básicos
Algoritmo de Dijkstra
- Va de un nodo origen al resto
Ejemplo
Inicialización
- Dijkstra es un algoritmo devorador (una vez que ha elegido a un nodo, no lo vuelve a usar)
Ejemplo
Ejercicio Dijkstra
Ejercicio
Conclusiones
- Dijkstra tiene una complejidad cuadrática O(n^2)
Algoritmo de Floyd-Warshall
Inicialización de la Matriz A
El algoritmo
- k es el pivote
- i es el origen
- j es el destino
Ejemplo 1 de Floyd-Warshall
- Lo marcado en rojo es el nodo intermedio a usar (Ej: Ir desde V1 hasta V6 usando como nodo intermedio V3)
Ejercicio 2
- Para hallar el camino inverso:
- Para ir del nodo V1 al nodo V5, usa el nodo intermedio V4
- Para ir del nodo V1 al nodo V4, hay camino directo (-)
- Para ir del nodo V4 al nodo V5, usa el nodo intermedio V3
- Para ir del nodo V3 al nodo V5, hay camino directo (-)
Algoritmo para almacenar la secuencia de nodos que forman todos los caminos de coste mínimo
- Se puede usar para hallar el camino inverso
private void printPath(int i, int j)
{
int k = P[i][j];
if (k>0) {
printPath (i, k);
System.out.print ('-' + k);
printPath (k, j);
}
}
System.out.print (departure);
printPath (departure, arrival);
System.out.println ('-' + arrival);
Floyd para rutas especiales
- Este ejercicio cayó en un examen
for (int k=0; k<size; k++)
if (k in L){
for (int i=0; i<size; i++){
for (int j=0; j<size; j++){
if (A[i][k] + A[k][j] < A[i][j])
{
A[i][j] = A[i][k] + A[k][j];
P[i][j] := k;
}
}
}
}
}
Centro de un grafo dirigido y excentricidad
Ejercicio: Obtener el centro de un grafo
Ejercicio: Hacer Floyd
FALTA
Recorrido en profundidad de un grafo (DFPrint)
boolean [] visited = new boolean [size];
public void resetVisited ()
{
for (int i=0; i<size; i++)
setVisited(i, false);
}
Ejercicio DFPrint
- Recorrido en profundidad V1: Saca por pantalla V1 V2 V4 V3
- Recorrido en profundidad V2: Saca por pantalla V2 V4 V3
- Recorrido en profundidad V3: Saca por pantalla V2 V4
- Recorrido en profundidad V2: Saca por pantalla V4 V3 V2
Búsqueda primero en profundidad
- Detiene el recorrido una vez se cumple una condición
Más conceptos básicos
- Nodo fuertemente conexo y grafo fuertemente conexo
- árbol abarcador
- árbol libre abarcador de coste mínimo
Algoritmo de Prim
- Sólo se aplica a grafos no dirigidos
- Busca cómo conectar todos los nodos del grafo con el árbol mínimo abarcador con el menor coste
Inicialización
Ejercicio 1
- Usaremos el criterio de la última arista escogida (porque tienen el mismo coste)
Ejercicio 2
Conclusiones
- Prim tiene complejidad O(n^3)