La clase Grafo La clase Vertice 4 Algoritmos de recorrido de

Anuncio
La clase Grafo
public class Grafo {
private
private
private
private
Tema 9: GRAFOS
Segunda Parte
Estructuras de Datos y Algoritmos
Curso 2002/03
static final int TAMANYO_INICIAL=10;
Vertice tabla [];
int numVertices;
TablaHash diccio;
public Grafo() { ... }
public insArista (String orig,String dest,int cost) { ... }
public String toString() { ... }
}
Grafos. EDA. Curso 2002/03
4 Algoritmos de recorrido de grafos
La clase Vertice
public class Vertice {
String nombre; //el nombre del vértice
Lista ady; // la lista de vértices adyacentes (aristas)
public Vertice(String v) {
nombre=v;
ady=new Lista();
Lista:
}
public
void insertar(Object x);
toString()
//public
la posiciónString
del punto de
interés continua {
apuntando al mismo elemento
public
void borrar()
throws DesbordamientoInferior;
return
ady.toString();
//}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
2
] DFS: recorrido en profundidad (Depth First Search),
generalización del recorrido en preorden de un árbol.
] BFS: recorrido en anchura (Breath First Search),
generalización del recorrido por niveles de un árbol.
3
Grafos. EDA. Curso 2002/03
4
Algoritmo de Recorrido en profundidad
Recorrido en profundidad (DFS)
] Explora sistemáticamente las aristas del grafo de forma que primero
se visitan los vértices adyacentes a los visitados más recientemente.
Así se va “profundizando” en el grafo.
] Algoritmo de recorrido en profundidad:
Método privado recursivo
DFS(v)
ordenRecorrido++; R[v]=ordenRecorrido;
wAdyacentes(v): Si (R[w]==0) entonces DFS(w)
\ Contador (ordenRecorrido)
\ Vector de naturales (R) para
[ “marcar” los vértices ya visitados (R[v]>0) y
[ almacenar el orden de recorrido. R[v]: orden en el que se visita el vértice v.
Grafos. EDA. Curso 2002/03
5
7
2
6
3
1
8
4
5
9
1
0
1/2,3,4,5
1
2
3/2,6,8
6/7
7/2 8/6
4/3,8
5/9/5,8
R
1
Grafos. EDA. Curso 2002/03
2
0
2
2
3
0
3
3
Grafos. EDA. Curso 2002/03
6
Recorrido en profundidad en Java
Ejemplo: Recorrido DFS
Nodos
v/w
Recorrido en Profundidad
ordenRecorrido=0; vV: R[v]=0;
vV: Si (R[v]==0) entonces DFS(v)
R mantiene el orden de recorrido
finRP
4
0
7
7
R
5
0
8
8
6
0
4
4
7
0
5
5
8
0
6
6
int R[];
int OrdenRecorrido;
public void RecorridoEnProfundidad () {
R=new int[numVertices];
OrdenRecorrido=1;
for (int i=0;i<numVertices;i++) R[i]=0;
for (int i=0; i<numVertices; i++) if (R[i]==0) DFS(i);
}
private void DFS (int i) {
R[i]=OrdenRecorrido++;
Lista b=tabla[i].ady;
b.inicio();
while (!b.esFin()) {
Arista w=(Arista) b.recupera();
if (R[w.dest]==0) DFS(w.dest);
b.siguiente();
}
}
9
0
9
9
7
Grafos. EDA. Curso 2002/03
8
Recorrido en anchura (BFS)
Ejercicio:
] Hacer una traza del recorrido en profundidad sobre el
grafo siguiente:
] Explora sistemáticamente las aristas del grafo de forma que primero
se visitan los vértices más “cercanos” al que estamos explorando.
] Algoritmo de recorrido en anchura:
\ V = { V0, V1,V2,V3,V4,V5,V6 }
\ E = { (VO,V1), (V0,V3), (V1,V3), (V1,V4), (V2,V0), (V2,V5), (V3,V4), (V3,V5),
(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
Algoritmo de Recorrido en anchura
Ejemplo: Recorrido BFS
Recorrido en Amplitud
OrdenRecorrido=0; vV: R[v]=0;
Q=new ColaEnlazada();
vV: Si (R[v]==0) entonces BFS(v)
R mantiene el orden de recorrido
7
2
Método privado para el recorrido en Amplitud
BFS(v)
OrdenRecorrido++; R[v]=OrdenRecorrido;
Q.insertar(v);
mientras (!Q.esVacia()) {
u=Q.quitarprimero();
wAdyacentes(u): Si R[w]==0 {
OrdenRecorrido++; R[w]=OrdenRecorrido; Q.insertar(w)
}
Grafos. EDA. Curso 2002/03
10
6
3
1
8
4
5
11
9
Nodos
v u w 1
1
1
1
2 3 4 5 2
3
2 6 8 4
3 8 5
6
7 8
6 7
9
9
5 8 1
R
2
0
2
2
Grafos. EDA. Curso 2002/03
3
0
3
3
4
0
4
4
R
5
0
5
5
Q
6
0
6
6
7
0
8
8
8
0
7
7
9
0
9
9
<1>
<>
<2>
<2,3>
<2,3,4>
<2,3,4,5>
<3,4,5>
<4,5>
-<4,5,6>
<4,5,6,8>
<5,6,8>
--<6,8>
<8>
<8,7>
<7>
-<>
<9>
<>
---
12
Recorrido en anchura en java
public void RecorridoEnAmplitud() {
R=new int[numVertices];OrdenRecorrido=1;q=new colaVec();
for (int i=0; i<numVertices; i++) R[i]=0;
for (int i=0; i<numVertices; i++) if (R[i]==0) BFS(i);
}
private void BFS (int v) {
R[v]=OrdenRecorrido++;
q.insertar(new Integer(v));
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
Ejercicio:
] Hacer una traza del recorrido en amplitud sobre el grafo
siguiente:
\ V = { V0, V1,V2,V3,V4,V5,V6 }
\ E = { (VO,V1), (V0,V3), (V1,V3), (V1,V4), (V2,V0), (V2,V5), (V3,V4), (V3,V5),
(V3,V6), (V4,V6), (V6,V5) }
13
14
Algoritmo de Ordenación Topológica
Ordenación topológica en GDA
] Aplicaciones:
\ Representación de las fases de un proyecto en un GDA
\ Evaluación de atributos en la fase de análisis semántico de un compilador
] Algoritmo para el recorrido según la OT
\ 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.
\ Basta ir anotando en una pila global (P) los vértices completamente
explorados por DFS.
Grafos. EDA. Curso 2002/03
Grafos. EDA. Curso 2002/03
OTP
ordenRecorrido=0;
vV: R[v]=0;
p= new pilaVec();
vV: Si (R[v]==0) entonces DFST(v) ;
Método privado recursivo
DFST(v)
ordenRecorrido++; R[v]=ordenRecorrido;
wAdyacentes(v): Si (R[w]==0) entonces DFST(w);
p.apilar(v);
15
Grafos. EDA. Curso 2002/03
16
Ejercicio
Ejemplo: Ordenación topológica
Nodos
v/w
7
2
6
3
1
8
4
5
9
9
1
5
4
1
0
1
1/2,3,4,5
2
3/2,6,8
6/7 7/2 --8/6 --4/3,8
5/--9/5,8
3
8
2
0
2
-
6
3
0
3
-
4
0
7
-
R
5
0
8
-
7
P
6
0
4
-
2
7
0
5
-
8
0
6
-
9
0
9
<>
<>
<2>
<2>
<2>
<7,2>
<6,7,2>
<8,6,7,2>
<3,8,6,7,2>
<4,3,8,6,7,2>
<5,4,3,8,6,7,2>
<1,5,4,3,8,6,7,2>
<9,1,5,4,3,8,6,7,2>
Grafo ordenado
topológicamente
Grafos. EDA. Curso 2002/03
Grafos. EDA. Curso 2002/03
17
BÚSQUEDA DE CAMINOS MÍNIMOS EN
GRAFOS
18
Problema: dado el siguiente grafo, encontrar el camino más
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
\ 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
] Problema del camino mínimo con pesos positivos
(algoritmo de Dijkstra)
v0
19
1
v1
v4
v3
v2
v5
\ La longitud del camino con pesos es la suma de los costes de las
aristas del camino
\ Las aristas tienen costes no negativos
\ Se trata de encontrar el camino más corto (medido con su coste
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
Implementación del algoritmo de Ordenación topológica en Java
v6
Problema0: encontrar el Camino más corto desde v2a v2
distancia
mínima
Solución0: //la
no
o longitud
0 de
//lahay
distancia
mínima
devv22aavv22es
es00
distanciaMin[vOrigen]
distanciaMin[vOrigen]=
=0;
0;;
Grafos. EDA. Curso 2002/03
20
Problema: dado el siguiente grafo, encontrar el camino más
v0
corto (medido por el número de aristas) desde su Vértice v2 a
cualquier otro vértice
v0
v5
v5
v4
v3
v2
v4
v3
v2
distanciaM[vOrigen]
distanciaM[vOrigen]=
= 0;
0;;
v1
v1
distanciaM[vOrigen]
distanciaM[vOrigen]== 0;
0;;
distanciaMin[primerVAdyacente(vOrigen)]
distanciaMin[primerVAdyacente(vOrigen)]==1;
1;;
...
...
distanciaMin[últimoVAdyacente(vOrigen)]
distanciaMin[últimoVAdyacente(vOrigen)]==1;
1;;
v6
Problema2: encontrar el Camino más corto desde v2 a los
Vértices más cercanos a los Vértices adyacentes a v2
v6
Solución
: los Vértices
más cercanos
son2sus
////distancia
mínima
es
(v adyacentes
no tiene)
2distancia
mínimade
devv00aavv1-v
1-v33 es 2 (v55 no tiene)
”
o
longitud
(mínima) 2
están
“a
2
Aristas
de
v
distanciaMin[primerVAdyacente(primerVAdyacente(vOrigen)]
==2;
2
distanciaMin[primerVAdyacente(primerVAdyacente(vOrigen)]
2;;
Problema1: encontrar el Camino más corto desde v2 a sus
Vértices más cercanos
¿ Cómo
////lala
distancia
mínima
de
a v sus
/v adyacentes,
es 1
Solución1: los
Vértices
más
cercanos
distancia
mínima
devv2son
2 a v00/v55 es 1
están “a 1 Arista de v2” olongitud (mínima)
distanciaMin[primerVAdyacente(vOrigen)]
=
distanciaMin[primerVAdyacente(vOrigen)]
=1;
1;1;
...
...
distanciaMin[últimoVAdyacente(vOrigen)]
distanciaMin[últimoVAdyacente(vOrigen)]=
=1;
1;;
Grafos. EDA. Curso 2002/03
Usar
una
recordar
Cola
dónde
seguir ?
21
distanciaMin[segundoVAdyacente(primerVAdyacente(vOrigen)]
distanciaMin[segundoVAdyacente(primerVAdyacente(vOrigen)]==2;
2;;
...
...
distanciaMin[últimoVAdyacente(primerVAdyacente(vOrigen)]
distanciaMin[últimoVAdyacente(primerVAdyacente(vOrigen)]==2;
2;;
...
...
distanciaMin[primerVAdyacente(últimoVAdyacente(vOrigen)]
distanciaMin[primerVAdyacente(últimoVAdyacente(vOrigen)]==2;
2;;
distanciaMin[segundoVAdyacente(últimoVAdyacente(vOrigen)]
distanciaMin[segundoVAdyacente(últimoVAdyacente(vOrigen)]==2;
2;;
...
...
distanciaMin[últimoVAdyacente(últimoVAdyacente(vOrigen)]
==2;
Grafos. EDA. Curso 2002/03
distanciaMin[últimoVAdyacente(últimoVAdyacente(vOrigen)]
2;;
22
Resolución del problema de caminos
mínimos sin pesos
Problema: dado un grafo, encontrar el camino más corto
(medido por el número de aristas) desde un Vértice dado,
origen, a cualquier otro vértice
CaminoMinimoSinPeso(origen)
Reformulación de Problema:
Recorrido en Anchura o Breath First Search (BFS) desde el
origen, en la que el vector R pasa a ser distanciaMin:
¾ distanciaMin[i] representa la distancia mínima de origen al
Vértice i
¾ si distanciaMin[i] == v, el Vértice i NO se ha visitado aún por lo
que la distancia mínima de origen al Vértice i es la máxima
posible
¾ distanciaMin[origen] == 0
¾ si distanciaMin[i] > 0, el Vértice i SÍ se ha visitado, desde un
cierto vAnterior/
vV: distanciaMin[v]=f ;
Coste del algoritmo: O(|E|)
distanciaMin[origen] = 0 ;
q.insertar(origen);
while ( !q.esVacia()) {
v=q.quitarprimero() ;
Lineal con el tamaño del grafo
(número de arcos)
wAdyacentes(v):
if (distanciaMin[w] == f) {
distanciaMin[w] = distanciaMin[v] + 1 ;
q.insertar(w);
}
distanciaMin[i]=distanciaMin[vAnterior] + 1
Grafos. EDA. Curso 2002/03
23
Grafos. EDA. Curso 2002/03
24
public void CaminoMinimoSinPeso(int origen){
Problema: dado el siguiente grafo, encontrar el camino más
distanciaMin = new int[numVertices];
for (int i=0 ; i<=numVertices ; i++) distanciaMin[i]=INFINITO ;
q=new ColaVec();
corto (medido por el número de aristas) desde su Vértice v2 a
cualquier otro vértice
v0
v5
0
2
2
2
0
0
5
v4
v3
v2
Vertice’s
v1
v6
Comprobar == inf evita
que distanciaMin[3]
pase a valer 3
|q
|q
|q
|q
|q
|q
= 2| q =
=0
= 0, 5
= 5, 1
= 5, 1, 3
= 1, 3
1|q = 3, 4
v
1
1
DistanciaMin
1 2 3 4 5
v 0vvv
- - - - - - - - 1
2 - - - - - 2 - - - - - - - - 3- - - - - - - - - 2 0 2 3
- 1
distanciaMin[origen]=0 ;
q.insertar(new Integer(origen));
try { while ( !q.esVacia()) {
int v=((Integer)q.quitarprimero())..intValue() ;
6
v
-
Lista b=tabla[v].ady;
b.inicio();
while ( !b.esFin()) {
Arista a = (Arista) b.recupera();
int w = a..dest();
if (distanciaMin[w] == INFINITO ) {
distanciaMin[w] = distanciaMin[v] + 1 ;
q.insertar(new Integer(w));
}
b.siguiente(); }
} catch (DesbordamientoInferior e) {// No puede ocurrir } }
distanciaMin[4] = distanciaMin[3] + 1
Grafos. EDA. Curso 2002/03
Grafos. EDA. Curso 2002/03
25
Encontrar no solo el coste sino también el
camino
26
Mostrar por pantalla el camino
Usar un vector para guardar el camino: P[i] es el vértice
anterior a i en el camino mínimo
void imprimirCamino(int destino) {
if (P[destino]!=-1) {
imprimirCamino(P[destino]);
CaminoMinimoSinPeso(origen)
vV: distanciaMin[v]=f ; vV: P[v]=-1 ;
}
distanciaMin[origen] = 0 ;
q.insertar(origen);
while ( !q.esVacia()) {
v=q.quitarprimero() ;
wAdyacentes(v):
System.out.println(tabla[destino].nombre);
}
if (distanciaMin[w] == f) {
P[w]=v;
distanciaMin[w] = distanciaMin[v] + 1 ;
q.insertar(w);
}
Grafos. EDA. Curso 2002/03
27
Grafos. EDA. Curso 2002/03
28
Resolución del problema de caminos
mínimos con pesos
Algoritmo de Dijkstra
Algoritmo de Dijkstra
] Cambio en el ajuste del vector de distancias
Dijkstra (origen)
\ El valor distanciaMin[v] sólo se modificaba una vez
\ Ahora el algoritmo debe decidir si para llegar a un cierto vértice
w es mejor pasar por v o no:
distanciaMin[w]=min(distanciaMin[w], distanciaMin[v]+coste(v,w))
] Cambio en la selección del vértice a tratar
\ Seleccionar el vértice más próximo ahora no es el tratado más
recientemente sino el de menor coste
vV: distanciaMin[v]=f ;
Coste del algoritmo: O(|V|2)
Mejora: Usar una Cola de Prioridad
distanciaMin[origen] = 0 ;
para representar C
C={V}; //todos los vértices por tratar
while ( C!=‡) {
v=el elemento de C con menor valor de distanciaMin;
Eliminar v de C;
wAdyacentes(v):
if (distanciaMin[w]>distanciaMin[v]+coste(v,w)) {
[ La estrategia NO es usar una cola (First-In First-Out)
[ El primero visitado no es el más próximo necesariamente
distanciaMin[w] = distanciaMin[v] + coste(v,w) ;
\ 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
Complejidad temporal (n=|V|)
30
Complejidad temporal (n=|V|)
Matriz de adyacencias y C una lista
Dijkstra (origen)
Listas de adyacencias y C un minHeap
Dijkstra (origen)
vV: distanciaMin[v]=f ;
vV: distanciaMin[v]=f ;
distanciaMin[origen] = 0 ;
4(n)
C={V}; //todos los vértices por tratar
n-1 iteraciones
while ( C!=‡) {
v=el elemento de C con menor valor de distanciaMin;
Eliminar v de C;
n 1
n(n 1)
distanciaMin[origen] = 0 ;
4(n)
C={V}; //todos los vértices por tratar
n-1 iteraciones
while ( C!=‡) {
v=el elemento de C con menor valor de distanciaMin;
Eliminar v de C;
n 1
wAdyacentes(v):
T ( n)
¦ k (n i )
i 1
k
if (distanciaMin[w]>distanciaMin[v]+coste(v,w)) {
2
 4( n 2 )
wAdyacentes(v):
¦ gradoG x log(n i)  4(| E | log n)
i 1
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:
|C|
Seleccionar
Eliminar
Grafos.
EDA.
Curso
2002/03
n-i
4(n-i)
4(n-i)
T ( n)
}
Bucle 4(n-i)
31
En la iteración i:
|C|
Seleccionar y Eliminar
n-i
4(log n-i)Grafos. EDA. Curso 2002/03
Bucle 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
int coste; // DistanciaMin[w]
\ Estructurar D como un minHeap
\ Implementar C como un vector de bits
\ Utilizar un vector para marcar la posición de cada vértice en el
heap
static ElementoHeap infNeg=new ElementoHeap();
ElementoHeap() {this(0);}
ElementoHeap (int d) { this(d,0);}
ElementoHeap (int d, int c) { dest=d; coste=c;}
] Opción 2:
\ Usar una cola de prioridad implementada como un minHeap en la
que cada elemento es un par (vértice, DistanciaMin[vértice])
\ Usar un vector para marcar los vértices ya visitados
(desencolados). De esta forma se trata las posibles repeticiones
de vértices en la cola de prioridad
public boolean menorQue (Comparable otro) {
return (coste< ((ElementoHeap)otro).coste);
}
public int compareTo (Object otro) {
return coste < ( (ElementoHeap)otro).coste ? -1 :
coste > ( (ElementoHeap)otro).coste ? 1 : 0;
}
[ Seguro que el vértice se trata con el menor valor de DistanciaMin
[ Ya no se vuelve a tratar porque se marca
Grafos. EDA. Curso 2002/03
}
Implementación del algoritmo de Dijkstra
34
Ejercicios:
public void dijkstra(int origen){
distanciaMin = new int[numVertices];
for (int i=0 ; i<=numVertices ; i++) distanciaMin[i] = INFINITO ;
qPrioridad = new MonticuloBinario(new
new ElementoHeap());
distanciaMin[vOrigen] = 0; qPrioridad.insertar(new ElementoHeap(origen, 0));
try { while ( !q.esVacia()) {
ElementoHeap par = ((ElementoHeap)q.eliminarMin()); v = par..dest();
if (desencolados[v] == 0) {
desencolados[v] = 1;
Lista b= tabla[v].ady(); b.inicio();
while ( !b.esFin()) {
Arista a = (Arista) b.recupera();
int w = a..dest; int costeVW = a..coste();
if ( distanciaMin[w] > distanciaMin[v] + costeVW) {
distanciaMin[w] = distanciaMin[v] + costeVW ;
qPrioridad.insertar(new ElementoQ(w, distanciaMin[w] ));
}
b.siguiente();
}
} catch (DesbordamientoInferior e) {// No puede ocurrir } }
Grafos. EDA. Curso 2002/03
Grafos. EDA. Curso 2002/03
33
35
1.- Hacer una traza del algoritmo de Dijkstra sobre este grafo, tomando como
2
vértice origen v2
v
v
4
v2
5
0
1
4
1
2 8
v5
v3
1
4 2
v6
10
v4
6
2.- Implementar en Java las operaciones sobre grafos, incluyendo recorridos y
obtención de caminos siguiendo los algoritmos vistos en clase
3.- Implementar en Java las operaciones sobre grafos, incluyendo recorridos y
obtención de caminos bajo el supuesto de que los grafos con los que vamos a
trabajar sean densos
Grafos. EDA. Curso 2002/03
36
Descargar