Transparencias Parte II

Anuncio
Tema 14 – Grafos y su Implementación en Java
Tema 14 – Grafos y su
Implementación en Java
Parte II
Germán Moltó
Escuela Técnica Superior de Ingeniería Informática
Índice general:
1.
Conceptos básicos sobre Grafos
2.
Representación de un Grafo: Matriz vs Listas de Adyacencia
3.
Representación de un Grafo Ponderado: la clase Adyacente
4.
Representación de un Grafo ponderado y etiquetado: La clase
GrafoDEtiquetado.
5.
Recorrido en Profundidad (DFS) de un Grafo
6.
Recorrido en Amplitud (BFS) de un Grafo
Universidad Politécnica de Valencia
1
Recorrido de un Grafo: Ampliación de la clase
Grafo


Los recorridos permiten obtener una secuencia de sus
elementos.
Recorrido en Profundidad o Depth First Search (DFS)




3
Recorrido en Profundidad (DFS) de un
Grafo
En Árboles Binarios conseguíamos hacer un recorrido en
profundidad de la siguiente manera:

PreOrden (Árbol) {
PreOrden(RaízÁrbol);
}
Generalización del Recorrido Pre-Orden de un Árbol
Explora las aristas del Grafo de manera que se visitan los
vértices adyacentes al recién visitado, con lo que se consigue
“profundizar” en las ramas del Grafo.
Recorrido en Anchura o Breadth First Search (BFS)

2
Generalización del Recorrido por Niveles de un Árbol.
Explora las Aristas del Grafo de manera que se visitan los
vértices adyacentes al explorado actualmente. Para cada uno
de esos vértices, se exploran sus vecinos, provocando un
recorrido en anchura.
tratar(RaízÁrbol);
Hijo(RaízÁrbol)
PreOrden(Hijo(RaízÁrbol));
En Grafos lo haremos de manera similar:

DFS(Grafo) {
 Verticei  Grafo
DFS(Verticei);
}
4
tratar(Vérticei);
 adyacente(Vérticei)
DFS(adyacente(Vérticei));
Gestión de Visitados para DFS
Ejemplo de Recorrido en Profundidad
b
b
4
aa
11
8
7
hh
8
2
i
7
c
2
f

9
a
2 (8)
3 (4)
2
h
3 (11)
1 (8)
4 (1)
3
b
1 (4)
2 (11)
6 (8)
4
g
....
5
i
....
....
....
6 c
5
.. ..

10
1
Utilizar atributos para marcar los Vértices ya visitados:

e
14
4
g
1
d


5 (7)
si visitados[i] == 0, el Vértice i NO se ha visitado aún
si visitados[i] > 0, el Vértice i SÍ se ha visitado.
El valor de visitados[i] indica el orden en el que se ha
visitado el Vértice:
De esta manera se interpretará:

visitados[3] = 5  El Vértice 3 se ha visitado en 5º posición, es
decir, antes se han visitado otros 4 vértices.
• Deberemos anotar los vértices ya visitados para no
recorrerlos varias veces.
• Utilizamos un vector de vértices ya visitados.
6
Traza de Recorrido en Profundidad: DFS (1/9)
• Vértice origen: 1
Vertice’s
7
2
6
3
1
8
4
5
7
9
1:2,3,4,5
2
3:2,6,8
6:7
7:2
8:6
4:3,8
5
9:5,8
1
0
11
1
2
0
2
2
3
0
3
3
visitados
4 5 6 7
0 0 0 0
- - - - - - - - - - - 4 - - - 5
- - - 7 - - - 8 - - - - 7 8 4 5
Traza de Recorrido en Profundidad: DFS (2/9)
Vertice’s
8
0
6
6
9
0
9
9
7
2
6
3
1
1
8
4
5
8
9
1:2,3,4,5
2
3:2,6,8
6:7
7:2
8:6
4:3,8
5
9:5,8
1
0
1
1
2
0
2
2
2
3
0
3
3
visitados
4 5 6 7
0 0 0 0
- - - - - - - - - - - 4 - - - 5
- - - 7 - - - 8 - - - - 7 8 4 5
8
0
6
6
9
0
9
9
Traza de Recorrido en Profundidad: DFS (3/9)
Vertice’s
7
2
6
3
1
1
8
4
5
1:2,3,4,5
2
3:2,6,8
6:7
7:2
8:6
4:3,8
5
9:5,8
9
1
0
1
1
2
0
2
2
3
0
33
3
visitados
4 5 6 7
0 0 0 0
- - - - - - - - - - - 4 - - - 5
- - - 7 - - - 8 - - - - 7 8 4 5
Traza de Recorrido en Profundidad: DFS (4/9)
Vertice’s
8
0
6
6
9
0
9
9
6
3
1
1
8
4
5
9
1:2,3,4,5
2
3:2,6,8
6:7
7:2
8:6
4:3,8
5
9:5,8
9
2
0
2
2
3
0
3
3
visitados
4 5 6 7
0 0 0 0
- - - - - - - - - - - 4 - - - 5
- - - 7 - - - 8 - - - - 7 8 4 5
8
0
6
6
9
0
9
9
10
Traza de Recorrido en Profundidad: DFS (5/9)
Vertice’s
7
2
6
3
1
1
8
4
5
11
7
2
1
0
1
1
9
1:2,3,4,5
2
3:2,6,8
6:7
7:2
8:6
4:3,8
5
9:5,8
1
0
1
1
2
0
2
2
3
0
3
3
visitados
4 5 6 7
0 0 0 0
- - - - - - - - - - - 44 - - - 5
- - - 7 - - - 8 - - - - 7 8 4 5
Traza de Recorrido en Profundidad: DFS (6/9)
Vertice’s
8
0
6
6
9
0
9
9
7
2
6
3
1
1
8
4
5
12
9
1:2,3,4,5
2
3:2,6,8
6:7
7:2
8:6
4:3,8
5
9:5,8
1
0
1
1
2
0
2
2
3
0
3
3
visitados
4 5 6 7
0 0 0 0
- - - - - - - - - - - 4 - - - 55
- - - 7 - - - 8 - - - - 7 8 4 5
8
0
6
6
9
0
9
9
Traza de Recorrido en Profundidad: DFS (7/9)
Vertice’s
7
2
6
3
1
1
8
4
5
1:2,3,4,5
2
3:2,6,8
6:7
7:2
8:6
4:3,8
5
9:5,8
9
1
0
1
1
2
0
2
2
3
0
3
3
visitados
4 5 6 7
0 0 0 0
- - - - - - - - - - - 4 - - - 5
- - - 7 - - - 8 - - - - 7 8 4 5
Traza de Recorrido en Profundidad: DFS (8/9)
Vertice’s
8
0
6
6
9
0
9
9
7
2
6
3
1
1
8
4
5
13
1:2,3,4,5
2
3:2,6,8
6:7
7:2
8:6
4:3,8
5
9:5,8
9
1
0
1
1
2
0
2
2
3
0
3
3
visitados
4 5 6 7
0 0 0 0
- - - - - - - - - - - 4 - - - 5
- - - 7 - - - 8 - - - - 7 8 4 5
9
0
9
9
8
0
6
6
9
0
9
9
14
Traza de Recorrido en Profundidad: DFS (9/9)
Vertice’s
7
2
6
3
1
1
8
4
5
9
1:2,3,4,5
2
3:2,6,8
6:7
7:2
8:6
4:3,8
5
9:5,8
.....
1
0
1
1
2
0
2
2
3
0
3
3
visitados
4 5 6 7
0 0 0 0
- - - - - - - - - - - 4 - - - 5
- - - 77 - - - 8 - - - - 7 8 4 5
8
0
6
6
9
0
9
9
Traza de Recorrido en Profundidad: DFS
(Final)
Vertice’s
7
2
6
3
1
8
4
5
9
1:2,3,4,5
2
3:2,6,8
6:7
7:2
8:6
4:3,8
5
9:5,8
1
0
1
1
2
0
2
2
3
0
3
3
visitados
4 5 6 7
0 0 0 0
- - - - - - - - - - - 4 - - - 5
- - - 7 - - - 8 - - - - 7 8 4 5
• La secuencia de vértices visitados (DFS) es: 1 2 3 6 7 8 4 5 9
15
8
0
6
6
6
16
Ampliación de la clase Grafo para
Soporte de DFS

Ampliamos la clase Grafo para soportar la
implementación del recorrido DFS.
public abstract class Grafo<E>{
protected int visitados[]; //Para el recorrido DFS
protected int ordenVisita; //Orden de visita de los vértices
public String toStringDFS() {...}
protected String arrayToString(int v[]){ … }
public int[] toArrayDFS() { … }
protected void toArrayDFS(int origen, int res[]) { … }
} /* Fin de la clase Grafo */
17
Métodos de Soporte para DFS (I)
public int[] toArrayDFS() {
int res[] = new int[numVertices() + 1];
visitados = new int[numVertices() + 1];
ordenVisita = 1;
for (int i = 1; i <= numVertices(); i++)
if ( visitados[i] == 0 ) toArrayDFS(i, res);
return res;
}
Es necesario realizar el bucle for por si
el grafo tiene varias componentes
conexas (en ese caso no sería posible
alcanzar todos los vértices desde el
vértice origen).
18
Métodos de Soporte para DFS (II)
Métodos de Soporte para DFS (III)
protected void toArrayDFS(int origen, int res[]) {
res[ordenVisita] = origen;
visitados[origen] = ordenVisita++;
ListaConPI<Adyacente> l = adyacentesDe(origen);
for (l.inicio(); !l.esFin(); l.siguiente()) {
Adyacente a = l.recuperar();
if (visitados[a.destino] == 0) toArrayDFS(a.destino, res);
}
}
El array res contiene directamente la
public String toStringDFS() {
return arrayToString(toArrayDFS());
}
secuencia de vértices en el orden en el
que son recorridos mediante DFS.
19
protected String arrayToString(int v[]){
StringBuilder sb = new StringBuilder();
for (int i = 1; i < v.length; i++)
sb.append(v[i] + "\n");
return sb.toString();
}
20
Recorrido en Anchura (BFS) de un
Grafo
• En Árboles Binarios conseguíamos
hacer un recorrido por niveles (o en
anchura) de la siguiente manera:
PorNiveles (Árbol) {
PorNiveles(RaízÁrbol);
}
• En Grafos se hace:
BFS(Grafo) {
Cola<Integer> q = new
ArrayCola<Integer>();
 Verticei  Grafo
BFS(Verticei);
}
Traza de Recorrido en Anchura: BFS
Cola<NodoABB<E>> q = new
ArrayCola<NodoABB<E>>();
q.encolar(RaízÁrbol);
mientras ( !q.esVacia() ){
r = q.desencolar();
tratar(r);
 Hijo(r): q.encolar(Hijo(r));
}
tratar(Vérticei); q.encolar(Vérticei);
mientras ( !q.esVacia() ) {
v = q.desencolar();
Adyacente(v):
tratar(Adyacente(v) );
q.encolar(Adyacente(v));
}
21
Traza de Recorrido en Anchura: BFS
(Final)
Vértice
• Vértice origen: 1
6
3
1
8
4
5
100000000
7
2
9
Visitados
Cola
123456789
000000000
1
1: 2 3 4 5
123450000
2345
2:
123450000
345
3: 2 6 8
123456070
4568
4: 3 8
123456070
568
5:
123456070
68
6: 7
123456870
87
8: 6
123456870
7
7: 2
123456870
9: 5 8
123456879
aa
11
8
0
7
h
2
i
1
7
cc
9
e
14
4
gg
dd
2
f
• Estado de la Cola de Vértices
por procesar:
0|
1| 2| 3| 4| 5| 6| 7|
10
• Vértice origen: a
a
1 (8)
2 (4)
1 h
2 (11)
0 (8)
3 (1)
2 b
0 (4)
1 (11)
5 (8)
3 g
6(2)
1 (1)
4
i
1 (7)
5 (2)
5
c
4 (2)
6 (4)
7 (7)
6 f
8 (10)
.. ..22 ........
7 (14)
5 (4)
4 (7)
Aunque en esta traza los
vértices se numeren de 0..N, de
normal los numeramos de 1..N
2 (8)
Ampliación de la clase Grafo para
Soporte de BFS
public abstract class Grafo<E>{
…
/** Para el recorrido DFS y BFS */
protected int visitados[];
protected int ordenVisita;
/** para el Recorrido en Anchura (BFS) */
protected Cola<Integer> q;
public String toStringBFS() { … }
public int[] toArrayBFS() { … }
protected void toArrayBFS(int origen, int res[]) { … }
} /* Fin de la clase Grafo */
• La secuencia de vértices visitados (BFS) es: 1 2 3 4 5 6 8 7 9
23
8
b
4
24
El método toArrayBFS (1/2)
El método toArrayBFS (2/2)
public String toStringBFS() {
protected void toArrayBFS(int origen, int res[]) {
res[ordenVisita] = origen;
visitados[origen] = ordenVisita++;
q.encolar(new Integer(origen));
while (!q.esVacia()) {
int u = q.desencolar().intValue();
ListaConPI<Adyacente> l = adyacentesDe(u);
for (l.inicio(); !l.esFin(); l.siguiente()) {
Adyacente a = l.recuperar();
if (visitados[a.destino] == 0) {
res[ordenVisita] = a.destino;
visitados[a.destino] = ordenVisita++;
q.encolar(new Integer(a.destino));
}
}
}
}
return arrayToString(toArrayBFS());
}
}
public int[] toArrayBFS() {
int res[] = new int[numVertices() + 1];
visitados = new int[numVertices() + 1];
ordenVisita = 1;
q = new ArrayCola<Integer>();
for ( int i = 1; i <= numVertices(); i++ )
if (visitados[i] == 0) toArrayBFS(i, res);
return res;
}
25
26
Aplicaciones de las Estrategias de
Recorrido

El recorrido en profundidad de un Grafo permite:



Determinar el número de componentes conexas, a partir del
número de invocaciones al método toArrayDFS desde el bucle
principal.
Determinar si un Grafo es acíclico. Si se trata de visitar un
nodo ya visitado entonces existe un ciclo en el Grafo.
El recorrido en anchura de un Grafo permite:


27
Exploración parcial de un grafo de tamaño elevado.
Encontrar el camino más corto entre dos nodos.
Descargar