You are on page 1of 9

La clase Grafo

public class Grafo {


private static final int TAMANYO_INICIAL=10;
private Vertice tabla [];
Tema 9: GRAFOS private int numVertices;
private TablaHash diccio;
Segunda Parte
Estructuras de Datos y Algoritmos public Grafo() { ... }

Curso 2002/03 public insArista (String orig,String dest,int cost) { ... }


public String toString() { ... }
}

Grafos. EDA. Curso 2002/03


2

La clase Vertice 4 Algoritmos de recorrido de grafos

public class Vertice {


String nombre; //el nombre del vértice
Lista ady; // la lista de vértices adyacentes (aristas) ] DFS: recorrido en profundidad (Depth First Search),
public Vertice(String v) { generalización del recorrido en preorden de un árbol.
nombre=v;
Lista:ady=new Lista();
}
public void insertar(Object x);
//public
la posiciónString toString()
del punto de interés continua {
apuntando al mismo elemento
] BFS: recorrido en anchura (Breath First Search),
public void borrar()
return throws DesbordamientoInferior;
ady.toString(); generalización del recorrido por niveles de un árbol.
//}borra el elemento que ocupa la posición del punto de interés (queda marcando al siguiente)
}public Object recupera();
public boolean esVacia();
public void inicio();
public void fin();
public void siguiente() throws PosicionIncorrecta;
public boolean esFin();
public String toString();

Grafos. EDA. Curso 2002/03 Grafos. EDA. Curso 2002/03


3 4
Recorrido en profundidad (DFS) Algoritmo de Recorrido en profundidad

Recorrido en Profundidad
] Explora sistemáticamente las aristas del grafo de forma que primero ordenRecorrido=0; vV: R[v]=0;
se visitan los vértices adyacentes a los visitados más recientemente. vV: Si (R[v]==0) entonces DFS(v)
Así se va “profundizando” en el grafo. R mantiene el orden de recorrido
finRP
] Algoritmo de recorrido en profundidad:
\ Contador (ordenRecorrido) Método privado recursivo
\ Vector de naturales (R) para DFS(v)
[ “marcar” los vértices ya visitados (R[v]>0) y ordenRecorrido++; R[v]=ordenRecorrido;
[ almacenar el orden de recorrido. R[v]: orden en el que se visita el vértice v. wAdyacentes(v): Si (R[w]==0) entonces DFS(w)

Grafos. EDA. Curso 2002/03 Grafos. EDA. Curso 2002/03


5 6

Ejemplo: Recorrido DFS Recorrido en profundidad en Java

int R[];
Nodos R int OrdenRecorrido;
v/w 1 2 3 4 5 6 7 8 9 public void RecorridoEnProfundidad () {
R=new int[numVertices];
7 0 0 0 0 0 0 0 0 0 OrdenRecorrido=1;
2 1/2,3,4,5 1 - - - - - - - - for (int i=0;i<numVertices;i++) R[i]=0;

6 2 - 2 - - - - - - - for (int i=0; i<numVertices; i++) if (R[i]==0) DFS(i);


}
3 3/2,6,8 - - 3 - - - - - - private void DFS (int i) {
1
6/7 - - - - - 4 - - - R[i]=OrdenRecorrido++;

8 7/2 - - - - - - 5 - - Lista b=tabla[i].ady;


b.inicio();
4 8/6 - - - - - - - 6 - while (!b.esFin()) {
4/3,8 - - - 7 - - - - - Arista w=(Arista) b.recupera();
5 9 5/- - - - - 8 - - - - if (R[w.dest]==0) DFS(w.dest);
b.siguiente();
9/5,8 - - - - - - - - 9 }
R 1 2 3 7 8 4 5 6 9 }

Grafos. EDA. Curso 2002/03 Grafos. EDA. Curso 2002/03


7 8
Ejercicio: Recorrido en anchura (BFS)

] Hacer una traza del recorrido en profundidad sobre el


grafo siguiente: ] Explora sistemáticamente las aristas del grafo de forma que primero
\ V = { V0, V1,V2,V3,V4,V5,V6 } se visitan los vértices más “cercanos” al que estamos explorando.
\ E = { (VO,V1), (V0,V3), (V1,V3), (V1,V4), (V2,V0), (V2,V5), (V3,V4), (V3,V5), ] Algoritmo de recorrido en anchura:
(V3,V6), (V4,V6), (V6,V5) } \ Contador (OrdenRecorrido)
\ Vector de naturales (R) para
[ “marcar” los vértices ya visitados (R[v]>0) y
[ almacenar el orden de recorrido.
\ Cola (Q) para gestionar los vértices no visitados
public interface cola {
void insertar (Object x);
Object quitarPrimero () throws DesbordamientoInferior;
Object primero () throws DesbordamientoInferior;
boolean esVacia();
void vaciar();
}

Grafos. EDA. Curso 2002/03 Grafos. EDA. Curso 2002/03


9 10

Algoritmo de Recorrido en anchura Ejemplo: Recorrido BFS


Nodos R Q
v u w 1 2 3 4 5 6 7 8 9
Recorrido en Amplitud 1 1 0 0 0 0 0 0 0 0 <1>
1 - - - - - - - - - <>
OrdenRecorrido=0; vV: R[v]=0; 2 - 2 - - - - - - - <2>
Q=new ColaEnlazada(); 3 - - 3 - - - - - - <2,3>
4 - - - 4 - - - - - <2,3,4>
vV: Si (R[v]==0) entonces BFS(v) 5 - - - - 5 - - - - <2,3,4,5>
7
R mantiene el orden de recorrido 2
2 - - - - - - - - - <3,4,5>
3 - - - - - - - - - <4,5>
2 - - - - - - - - - --

Método privado para el recorrido en Amplitud 6 6 - - - - - 6 - - - <4,5,6>


3 8 - - - - - - - 7 - <4,5,6,8>
BFS(v) 4 - - - - - - - - - <5,6,8>
3 - - - - - - - - - --
OrdenRecorrido++; R[v]=OrdenRecorrido; 1 8 - - - - - - - - - --
Q.insertar(v); 5 - - - - - - - - - <6,8>
8 6 - - - - - - - - - <8>
mientras (!Q.esVacia()) { 4 7 - - - - - - 8 - - <8,7>
u=Q.quitarprimero(); 8 - - - - - - - - - <7>
6 - - - - - - - - - --
wAdyacentes(u): Si R[w]==0 { 5 9 7 - - - - - - - - - <>
OrdenRecorrido++; R[w]=OrdenRecorrido; Q.insertar(w) 9 - - - - - - - - 9 <9>
9 - - - - - - - - - <>
} 5 - - - - - - - - - --
8 - - - - - - - - - --
R 1 2 3 4 5 6 8 7 9

Grafos. EDA. Curso 2002/03 Grafos. EDA. Curso 2002/03


11 12
Recorrido en anchura en java Ejercicio:
public void RecorridoEnAmplitud() {
R=new int[numVertices];OrdenRecorrido=1;q=new colaVec(); ] Hacer una traza del recorrido en amplitud sobre el grafo
for (int i=0; i<numVertices; i++) R[i]=0;
for (int i=0; i<numVertices; i++) if (R[i]==0) BFS(i); siguiente:
} \ V = { V0, V1,V2,V3,V4,V5,V6 }
private void BFS (int v) {
R[v]=OrdenRecorrido++; \ E = { (VO,V1), (V0,V3), (V1,V3), (V1,V4), (V2,V0), (V2,V5), (V3,V4), (V3,V5),
q.insertar(new Integer(v)); (V3,V6), (V4,V6), (V6,V5) }
while (!q.esVacia()) {
Integer u= (Integer) q.quitarPrimero();
Lista b=tabla[u.intValue()].ady;
b.primero();
while (!b.esFin()) {
Arista w=(Arista) b.recupera();
if (R[w.dest]==0) {
R[w.dest]=OrdenRecorrido++;
q.insertar(new Integer(w.dest));
}
b.siguiente();
}
}
} Grafos. EDA. Curso 2002/03 Grafos. EDA. Curso 2002/03
13 14

Ordenación topológica en GDA Algoritmo de Ordenación Topológica

OTP
] Aplicaciones: ordenRecorrido=0;
\ Representación de las fases de un proyecto en un GDA vV: R[v]=0;
\ Evaluación de atributos en la fase de análisis semántico de un compilador p= new pilaVec();
] Algoritmo para el recorrido según la OT vV: Si (R[v]==0) entonces DFST(v) ;
\ Utilizar el recorrido en profundidad para ordenar los vértices según un
orden (parcial) “½“ tal que u,vV, si (u,v)E, u ½ v. Método privado recursivo
\ Basta ir anotando en una pila global (P) los vértices completamente DFST(v)
explorados por DFS.
ordenRecorrido++; R[v]=ordenRecorrido;
wAdyacentes(v): Si (R[w]==0) entonces DFST(w);
p.apilar(v);

Grafos. EDA. Curso 2002/03 Grafos. EDA. Curso 2002/03


15 16
Ejemplo: Ordenación topológica Ejercicio

Nodos R P
v/w 1 2 3 4 5 6 7 8 9
0 0 0 0 0 0 0 0 0 <> Implementación del algoritmo de Ordenación topológica en Java
7 1/2,3,4,5 1 - - - - - - - - <>
2
2 - 2 - - - - - - - <2>
6 3/2,6,8 - - 3 - - - - - - <2>
3 6/7 - - - - - 4 - - - <2>
7/2 - - - - - - 5 - - <7,2>
1 --- - - - - - - - - - <6,7,2>
8 8/6 - - - - - - - 6 - <8,6,7,2>
4 --- - - - - - - - - - <3,8,6,7,2>
4/3,8 - - - 7 - - - - - <4,3,8,6,7,2>
5/- - - - - 8 - - - - <5,4,3,8,6,7,2>
5 9 --- - - - - - - - - - <1,5,4,3,8,6,7,2>
9/5,8 - - - - - - - - 9 <9,1,5,4,3,8,6,7,2>

Grafo ordenado
9 1 5 4 3 8 6 7 2 topológicamente
Grafos. EDA. Curso 2002/03 Grafos. EDA. Curso 2002/03
17 18

BÚSQUEDA DE CAMINOS MÍNIMOS EN Problema: dado el siguiente grafo, encontrar el camino más
GRAFOS corto (medido por el número de aristas) desde su Vértice v2 a
cualquier otro vértice
] Problema del camino mínimo sin pesos
v0 1 v1
\ La longitud del camino sin pesos mide el número de aristas
\ Encontrar el camino más corto (medido por el número de aristas)
desde un cierto vértice O a cualquier otro vértice v2 v3 v4
] Problema del camino mínimo con pesos positivos
(algoritmo de Dijkstra) v5 v6
\ La longitud del camino con pesos es la suma de los costes de las
aristas del camino Problema0: encontrar el Camino más corto desde v2a v2
\ Las aristas tienen costes no negativos Solución0: //la
no distancia
//lahay mínima
o longitud
distancia 0 de
mínima devv22aavv22es
es00
\ Se trata de encontrar el camino más corto (medido con su coste distanciaMin[vOrigen]
distanciaMin[vOrigen]=
=0;
0;;
total) desde el vértice origen al resto de vértices
\ El problema anterior es un particular de éste, en el que las aristas
tiene coste 1

Grafos. EDA. Curso 2002/03 Grafos. EDA. Curso 2002/03


19 20
distanciaM[vOrigen]
distanciaM[vOrigen]== 0;
0;;
distanciaMin[primerVAdyacente(vOrigen)]
distanciaMin[primerVAdyacente(vOrigen)]==1;
Problema: dado el siguiente grafo, encontrar el camino más v0 v1 1;;
...
...
corto (medido por el número de aristas) desde su Vértice v2 a
distanciaMin[últimoVAdyacente(vOrigen)]
distanciaMin[últimoVAdyacente(vOrigen)]==1;
1;;
cualquier otro vértice v2 v3 v4

distanciaM[vOrigen]
distanciaM[vOrigen]=
= 0;
0;;
v0 v1 v5 v6

v2 v3 v4
Problema2: encontrar el Camino más corto desde v2 a los
Vértices más cercanos a los Vértices adyacentes a v2
v5 v6
Solución : los Vértices
////distancia mínimamás cercanos son2sus
(v adyacentes
2distancia mínimade
devv00aavv1-v es no tiene)
1-v33 es 2 (v55 no tiene)
Problema1: encontrar el Camino más corto desde v2 a sus están “a 2 Aristas de v 2 ” o longitud (mínima) 2
distanciaMin[primerVAdyacente(primerVAdyacente(vOrigen)]
distanciaMin[primerVAdyacente(primerVAdyacente(vOrigen)] ==2;
2;;
Vértices más cercanos ¿ Cómo distanciaMin[segundoVAdyacente(primerVAdyacente(vOrigen)]
distanciaMin[segundoVAdyacente(primerVAdyacente(vOrigen)]==2; 2;;
////lala distancia mínima de ...
Solución1: los Vértices más
distancia mínima devv2son
cercanos a v sus es 1
/v adyacentes,
2 a v00/v55 es 1 Usar una
recordar
...
distanciaMin[últimoVAdyacente(primerVAdyacente(vOrigen)]
distanciaMin[últimoVAdyacente(primerVAdyacente(vOrigen)]==2;
2;;
están “a 1 Arista de v2” olongitud (mínima)
distanciaMin[primerVAdyacente(vOrigen)]
distanciaMin[primerVAdyacente(vOrigen)] = 1;1;
=1; ...
...
Cola
dónde distanciaMin[primerVAdyacente(últimoVAdyacente(vOrigen)]
distanciaMin[primerVAdyacente(últimoVAdyacente(vOrigen)]==2;
2;;
...
...
distanciaMin[segundoVAdyacente(últimoVAdyacente(vOrigen)]
distanciaMin[segundoVAdyacente(últimoVAdyacente(vOrigen)]==2; 2;;
distanciaMin[últimoVAdyacente(vOrigen)]
distanciaMin[últimoVAdyacente(vOrigen)]=
=1;
1;; seguir ? ...
...
Grafos. EDA. Curso 2002/03 distanciaMin[últimoVAdyacente(últimoVAdyacente(vOrigen)]
distanciaMin[últimoVAdyacente(últimoVAdyacente(vOrigen)]
Grafos. EDA. Curso 2002/03 ==2;
2;;
21 22

Problema: dado un grafo, encontrar el camino más corto Resolución del problema de caminos
(medido por el número de aristas) desde un Vértice dado, mínimos sin pesos
origen, a cualquier otro vértice

Reformulación de Problema: CaminoMinimoSinPeso(origen)


 vV: distanciaMin[v]=f ; Coste del algoritmo: O(|E|)
Recorrido en Anchura o Breath First Search (BFS) desde el Lineal con el tamaño del grafo
distanciaMin[origen] = 0 ;
origen, en la que el vector R pasa a ser distanciaMin: q.insertar(origen); (número de arcos)
¾ distanciaMin[i] representa la distancia mínima de origen al while ( !q.esVacia()) {
Vértice i v=q.quitarprimero() ;
¾ si distanciaMin[i] == v, el Vértice i NO se ha visitado aún por lo  wAdyacentes(v):
que la distancia mínima de origen al Vértice i es la máxima if (distanciaMin[w] == f) {
posible distanciaMin[w] = distanciaMin[v] + 1 ;
¾ distanciaMin[origen] == 0 q.insertar(w);
¾ si distanciaMin[i] > 0, el Vértice i SÍ se ha visitado, desde un }
cierto vAnterior/
distanciaMin[i]=distanciaMin[vAnterior] + 1
Grafos. EDA. Curso 2002/03 Grafos. EDA. Curso 2002/03
23 24
public void CaminoMinimoSinPeso(int origen){
Problema: dado el siguiente grafo, encontrar el camino más distanciaMin = new int[numVertices];
corto (medido por el número de aristas) desde su Vértice v2 a for (int i=0 ; i<=numVertices ; i++) distanciaMin[i]=INFINITO ;
cualquier otro vértice q=new ColaVec();

distanciaMin[origen]=0 ;
v0 v1 Vertice’s DistanciaMin q.insertar(new Integer(origen));
0 1 2 3 4 5 6
try { while ( !q.esVacia()) {
2 |q = 2| q = v v 0vvv v
v2 v3 v4 int v=((Integer)q.quitarprimero())..intValue() ;
2 |q =0 1 - - - - - -
2 |q = 0, 5 - - - - - 1 - Lista b=tabla[v].ady;
0 |q = 5, 1 - 2 - - - - - b.inicio();
v5 v6
0 |q = 5, 1, 3 - - - 2 - - - while ( !b.esFin()) {
5 |q = 1, 3 - - - - - - - Arista a = (Arista) b.recupera();
Comprobar == inf evita 1|q = 3, 4 - - - - 3- - -
int w = a..dest();
- - - - - - -
que distanciaMin[3] - - - - - - -
if (distanciaMin[w] == INFINITO ) {
pase a valer 3 1 2 0 2 3 - 1 - distanciaMin[w] = distanciaMin[v] + 1 ;
q.insertar(new Integer(w));
}
distanciaMin[4] = distanciaMin[3] + 1 b.siguiente(); }
} catch (DesbordamientoInferior e) {// No puede ocurrir } }
Grafos. EDA. Curso 2002/03 Grafos. EDA. Curso 2002/03
25 26

Encontrar no solo el coste sino también el


camino Mostrar por pantalla el camino

Usar un vector para guardar el camino: P[i] es el vértice void imprimirCamino(int destino) {
anterior a i en el camino mínimo if (P[destino]!=-1) {
CaminoMinimoSinPeso(origen) imprimirCamino(P[destino]);
 vV: distanciaMin[v]=f ;  vV: P[v]=-1 ; }
distanciaMin[origen] = 0 ; System.out.println(tabla[destino].nombre);
q.insertar(origen); }
while ( !q.esVacia()) {
v=q.quitarprimero() ;
 wAdyacentes(v):
if (distanciaMin[w] == f) {
P[w]=v;
distanciaMin[w] = distanciaMin[v] + 1 ;
q.insertar(w);
} Grafos. EDA. Curso 2002/03 Grafos. EDA. Curso 2002/03
27 28
Resolución del problema de caminos
mínimos con pesos Algoritmo de Dijkstra

Algoritmo de Dijkstra
Dijkstra (origen)
] Cambio en el ajuste del vector de distancias  vV: distanciaMin[v]=f ;
Coste del algoritmo: O(|V|2)
\ El valor distanciaMin[v] sólo se modificaba una vez Mejora: Usar una Cola de Prioridad
distanciaMin[origen] = 0 ;
\ Ahora el algoritmo debe decidir si para llegar a un cierto vértice C={V}; //todos los vértices por tratar para representar C
w es mejor pasar por v o no:
while ( C!=‡) {
distanciaMin[w]=min(distanciaMin[w], distanciaMin[v]+coste(v,w)) v=el elemento de C con menor valor de distanciaMin;
] Cambio en la selección del vértice a tratar Eliminar v de C;
\ Seleccionar el vértice más próximo ahora no es el tratado más  wAdyacentes(v):
recientemente sino el de menor coste if (distanciaMin[w]>distanciaMin[v]+coste(v,w)) {
[ La estrategia NO es usar una cola (First-In First-Out) distanciaMin[w] = distanciaMin[v] + coste(v,w) ;
[ El primero visitado no es el más próximo necesariamente }
\ En general utilizaremos un conjunto C para guardar los vértices no
tratados: al principio son todos y en cada iteración se elimina uno,
aquel que tiene el valor de distanciaMin menor.
Grafos. EDA. Curso 2002/03 Grafos. EDA. Curso 2002/03
29 30

Complejidad temporal (n=|V|) Complejidad temporal (n=|V|)


Matriz de adyacencias y C una lista Listas de adyacencias y C un minHeap
Dijkstra (origen) Dijkstra (origen)
 vV: distanciaMin[v]=f ;  vV: distanciaMin[v]=f ;
distanciaMin[origen] = 0 ; 4(n) distanciaMin[origen] = 0 ; 4(n)
C={V}; //todos los vértices por tratar C={V}; //todos los vértices por tratar
while ( C!=‡) { n-1 iteraciones while ( C!=‡) { n-1 iteraciones
v=el elemento de C con menor valor de distanciaMin; v=el elemento de C con menor valor de distanciaMin;
Eliminar v de C; n 1
n(n  1) Eliminar v de C; n 1

 wAdyacentes(v): T ( n) ¦ k (n  i ) k  4( n 2 )  wAdyacentes(v): T ( n) ¦ gradoG x log(n  i)  4(| E | log n)


i 1 2 i 1
if (distanciaMin[w]>distanciaMin[v]+coste(v,w)) { if (distanciaMin[w]>distanciaMin[v]+coste(v,w)) {
distanciaMin[w] = distanciaMin[v] + coste(v,w) ; distanciaMin[w] = distanciaMin[v] + coste(v,w) ;
} }
En la iteración i: En la iteración i:
|C| Seleccionar Eliminar Bucle  |C| Seleccionar y Eliminar Bucle 
n-i 4(n-i) Grafos. EDA. Curso 4(n-i)
2002/03 4(n-i) 31
n-i 4(log n-i)Grafos. EDA. Curso 2002/03 4(gradoG log (n-i))
32
Implementación del algoritmo de Dijkstra La clase ElementoHeap

] Opción 1: public class ElementoHeap implements Comparable{


int dest; // vértice w
\ Estructurar D como un minHeap
int coste; // DistanciaMin[w]
\ Implementar C como un vector de bits
\ Utilizar un vector para marcar la posición de cada vértice en el static ElementoHeap infNeg=new ElementoHeap();
heap ElementoHeap() {this(0);}
] Opción 2: ElementoHeap (int d) { this(d,0);}
ElementoHeap (int d, int c) { dest=d; coste=c;}
\ Usar una cola de prioridad implementada como un minHeap en la
que cada elemento es un par (vértice, DistanciaMin[vértice]) public boolean menorQue (Comparable otro) {
\ Usar un vector para marcar los vértices ya visitados return (coste< ((ElementoHeap)otro).coste);
(desencolados). De esta forma se trata las posibles repeticiones }
de vértices en la cola de prioridad public int compareTo (Object otro) {
[ Seguro que el vértice se trata con el menor valor de DistanciaMin return coste < ( (ElementoHeap)otro).coste ? -1 :
[ Ya no se vuelve a tratar porque se marca coste > ( (ElementoHeap)otro).coste ? 1 : 0;
}
}
Grafos. EDA. Curso 2002/03 Grafos. EDA. Curso 2002/03
33 34

Implementación del algoritmo de Dijkstra Ejercicios:

public void dijkstra(int origen){ 1.- Hacer una traza del algoritmo de Dijkstra sobre este grafo, tomando como
distanciaMin = new int[numVertices]; 2
vértice origen v2 v v
for (int i=0 ; i<=numVertices ; i++) distanciaMin[i] = INFINITO ; 0 1
qPrioridad = new MonticuloBinario(new new ElementoHeap()); 4 10
distanciaMin[vOrigen] = 0; qPrioridad.insertar(new ElementoHeap(origen, 0)); 4 1
try { while ( !q.esVacia()) { v2 v3 v4
2 8 4 2
ElementoHeap par = ((ElementoHeap)q.eliminarMin()); v = par..dest();
if (desencolados[v] == 0) { 5 6
v5 v6
desencolados[v] = 1; 1
Lista b= tabla[v].ady(); b.inicio();
while ( !b.esFin()) { 2.- Implementar en Java las operaciones sobre grafos, incluyendo recorridos y
Arista a = (Arista) b.recupera(); obtención de caminos siguiendo los algoritmos vistos en clase
int w = a..dest; int costeVW = a..coste();
if ( distanciaMin[w] > distanciaMin[v] + costeVW) {
3.- Implementar en Java las operaciones sobre grafos, incluyendo recorridos y
distanciaMin[w] = distanciaMin[v] + costeVW ;
qPrioridad.insertar(new ElementoQ(w, distanciaMin[w] ));
obtención de caminos bajo el supuesto de que los grafos con los que vamos a
} trabajar sean densos
b.siguiente();
}
} catch (DesbordamientoInferior e) {// No puede ocurrir } }
Grafos. EDA. Curso 2002/03 Grafos. EDA. Curso 2002/03
35 36

You might also like