1. Estructuras de Datos y Algoritmos
Facultad de Inform´tica
a
Universidad Polit´cnica de Valencia
e
Curso 2008/2009
Tema 4:
Grafos y ´rboles
a
FI– UPV: Curso 2008/2009
2. EDA-4
TEMA 4. Grafos y ´rboles
a
Objetivos
• Definiciones, representaci´n y recorrido de ´rboles y grafos.
o a
Contenidos
1 Grafos: Definiciones b´sicas
a
2 Representaci´n de grafos
o
3 ´
Arboles: Definiciones b´sicas
a
4 ´
Arboles binarios
5 Representaci´n de ´rboles
o a
6 Recorridos de ´rboles binarios
a
7 Recorrido de grafos
8 Orden topol´gico en grafos ac´
o ıclicos
Bibliograf´
ıa
• Introduction to Algorithms, de Cormen, Leiserson y Rivest (sec. 5.4, 5.5, 11.4 y 23.1)
• Estructuras de datos y algoritmos, de Aho, Hopcroft y Ullman (cap´ ıtulos 3, 6 y 7)
FI– UPV: Curso 2008/2009 P´gina 4.1
a
3. EDA-4
´
1. GRAFOS: DEFINICIONES BASICAS
Grafo dirigido: es un par G = (V, A) donde V es un conjunto finito de elementos
llamados v´rtices y A ⊆ V × V es un conjunto de “pares ordenados” de v´rtices llamados
e e
aristas.
Si (u, v) es una arista de G, se dice que el v´rtice v es adyacente a u.
e
0 1 2
3 4 5
FI– UPV: Curso 2008/2009 P´gina 4.2
a
4. EDA-4
´
1. GRAFOS: DEFINICIONES BASICAS
Grafo no dirigido: es un par G = (V, A) donde V es un conjunto finito de v´rtices y
e
A ⊆ {{u, v} | u, v ∈ V ∧ v = u} es un conjunto de “pares no ordenados” de v´rtices.
e
Si a = {u, v} es una arista no dirigida, se dice que a une a u y v y que a incide en u y v.
Si {u, v} es una arista de G, se dice que el v´rtice v es adyacente a u. La relaci´n es
e o
sim´trica.
e
0 1
2
4 3
FI– UPV: Curso 2008/2009 P´gina 4.3
a
5. EDA-4
´
1. GRAFOS: DEFINICIONES BASICAS
Grado: para todo v´rtice v,
e
• grado de entrada es el n´mero de aristas que inciden en v;
u
• grado de salida es el n´mero de aristas que emergen de v;
u
• grado es la suma de los grados de entrada y salida de v.
El grado de un grafo es el m´ximo grado de sus v´rtices.
a e
0 1 2
3 4 5
Ejem.: El grado de entrada del v´rtice 1 es 2; el grado de salida es 1; el grado del v´rtice es 3. El grado del
e e
grafo es 3.
FI– UPV: Curso 2008/2009 P´gina 4.4
a
6. EDA-4
´
1. GRAFOS: DEFINICIONES BASICAS
Camino desde un v´rtice u ∈ V a un v´rtice v ∈ V : es una secuencia v0, v1, . . . , vk de
e e
v´rtices de G = (V, A) tal que v0 = u, vk = v, (vi, vi+1) ∈ A, 0 ≤ i < k.
e
La longitud de un camino v0, v1, . . . , vk es el n´mero de aristas que lo forman.
u
Camino simple: es un camino v0, v1, . . . , vk en el que todos sus v´rtices son distintos,
e
excepto quiz´s el primero y el ultimo.
a ´
Ciclo: es un camino simple v0, v1, . . . , vk tal que v0 = vk y el camino contiene al menos
una arista.
Un bucle es un ciclo de longitud 1.
0 1 2
3 4 5
Ejem.: El camino 0, 3, 1, 4 es simple y tiene longitud 3. El camino 0, 1, 4, 3, 1 no es simple.
Ejem.: El camino 1, 4, 3, 1 es un ciclo de longitud 3. El ciclo 5, 5 es un bucle.
Grafo ac´
ıclico: es un grafo sin ciclos.
FI– UPV: Curso 2008/2009 P´gina 4.5
a
7. EDA-4
´
1. GRAFOS: DEFINICIONES BASICAS
Subgrafo: G = (V , A ) es un subgrafo de G = (V, A) si V ⊆ V ∧ A ⊆ A.
Subgrafo inducido: Dado V ⊆ V , el subgrafo de G inducido por V es G = (V , A )
tal que A = {(u, v) ∈ A | u, v ∈ V }.
0 1 2
3 4 5
0 1 0 1
3 4 3 4
Subgrafo Subgrafo inducido por V = {0, 1, 3, 4}
FI– UPV: Curso 2008/2009 P´gina 4.6
a
8. EDA-4
´
1. GRAFOS: DEFINICIONES BASICAS
V´rtice alcanzable desde un v´rtice u: es cualquier v´rtice v para el que existe un
e e e
camino de u a v.
Las componentes conexas en un grafo no dirigido son las clases de equivalencia de
v´rtices seg´n la relaci´n “ser alcanzable”.
e u o
• Un grafo no dirigido es conexo si ∀u, v ∈ V , v es alcanzable desde u. Es decir, si tiene
una unica componente conexa.
´
Las componentes fuertemente conexas en un grafo dirigido son las clases de
equivalencia de v´rtices seg´n la relaci´n “ser mutuamente alcanzable”.
e u o
• Un grafo dirigido es fuertemente conexo si ∀u, v ∈ V , v es alcanzable desde u.
0 1 0 1 2
2
4 3 3 4 5
FI– UPV: Curso 2008/2009 P´gina 4.7
a
9. EDA-4
´
1. GRAFOS: DEFINICIONES BASICAS
Grafo completo: es un grafo G = (V, A) en el que ∀u, v ∈ V , u = v, (u, v) ∈ A.
Grafo etiquetado: es un grafo G = (V, A) acompa˜ado de una funci´n f : A → E,
n o
donde E es un conjunto cuyas componentes se denominan etiquetas.
Grafo ponderado: es un grafo etiquetado con n´meros reales (E ≡ R).
u
2
Un grafo se considera denso si |A| ≈ |V | .
2
Un grafo se considera disperso si |A| <<< |V | .
FI– UPV: Curso 2008/2009 P´gina 4.8
a
10. EDA-4
´
2. REPRESENTACION DE GRAFOS: Matriz de adyacencias
Un grafo G = (V, A) se representa como G: matriz[V, V ] de booleanos. La componente
G[u, v] es 1 si (u, v) ∈ A; sino G[u, v] = 0.
Memoria: O(|V |2) → grafos densos |A| ≈ |V |2.
Tiempo de acceso: O(1). Lista adyacentes: O(|V |). Lista incidentes: O(|V |).
0 0 1 0 1 0 0
0 1 2 1 0 0 0 0 1 0
2 0 0 0 0 1 1
3 0 1 0 0 0 0
4 0 0 0 1 0 0
3 4 5
5 0 0 0 0 0 1
0 0 1 0 0 1
0 1 1 1 0 1 1 1
2 0 1 0 1 0
2
3 0 1 1 0 1
4 3 4 1 1 0 1 0
FI– UPV: Curso 2008/2009 P´gina 4.9
a
11. EDA-4
1 // Representacion de Grafos: Matriz de adyacencia
2 #include <vector>
3 #include <iostream>
4 using namespace std;
5 class grafoDirigidoBitMat {
6 int numVert;
7 vector<bool> vec;
8 int indice(int u, int v) const { return u*numVert+v; }
9 public:
10 grafoDirigidoBitMat(int nvert) : numVert(nvert),vec(nvert*nvert) {}
11 void insertar_arista(int u, int v) { vec[indice(u,v)] = true; }
12 bool existe_arista(int u, int v) const { return vec[indice(u,v)]; }
13 void imprime(ostream &s) const;
14 };
15 void grafoDirigidoBitMat::imprime(ostream &s) const {
16 for (int u=0; u < numVert; ++u) {
17 for (int v=0; v < numVert; ++v)
18 s << ((vec[indice(u,v)]) ? ’1’ : ’0’) << ’ ’;
19 s << endl;
20 }
21 }
FI– UPV: Curso 2008/2009 P´gina 4.10
a
12. EDA-4
22 ostream& operator << (ostream& s, const grafoDirigidoBitMat &grafo) {
23 grafo.imprime(s); return s;
24 }
25 int main(int argc, char *argv[]) {
26 if (argc != 2) {
27 cerr << "Uso: " << argv[0] << " maxNodosn"; exit(0);
28 }
29 int numVert = atoi(argv[1]);
30 grafoDirigidoBitMat gdmat(numVert);
31 int u,v;
32 while (cin >> u >> v) { // lectura de aristas
33 if (0<=u && u<numVert && 0<=v && v<numVert)
34 gdmat.insertar_arista(u, v);
35 }
36 // volcamos la matriz por salida estandar
37 cout << "nMatriz de adyacencian" << gdmat << endl;
38 return 0;
39 }
FI– UPV: Curso 2008/2009 P´gina 4.11
a
13. EDA-4
´
2. REPRESENTACION DE GRAFOS: Listas de adyacencia
Un grafo G = (V, A) se representa como un vector de listas de v´rtices indexado por v´rtices;
e e
es decir, G: vector[V ] de V . Cada componente G[v] es una lista de los v´rtices emergentes
e
y/o incidentes de/a v ∈ V .
Memoria: O(|V | + |A|) → grafos dispersos |A| <<< |V |2.
Tiempo de acceso: O(grado(G)). Lista adyacentes: O(grado(G)). (Lista incidentes:
O(grado(G)) con listas de incidencia.)
0 1 3 NIL
0 1 2 1 4 NIL
2 4 5 NIL
3 1 NIL
4 3 NIL
3 4 5
5 5 NIL
0 1 4 NIL
0 1 1 0 4 3 2 NIL
2 3 1 NIL
2
3 4 2 1 NIL
4 3 4 3 0 1 NIL
FI– UPV: Curso 2008/2009 P´gina 4.12
a
14. EDA-4
1 // Representacion de Grafos: Listas de adyacencia
2 #include <iostream>
3 using namespace std;
4 class grafoListaAd {
5 struct arista {
6 int vertice_destino;
7 arista *sig;
8 arista (int v, arista *s) { vertice_destino=v; sig=s; }
9 };
10 int numVert;
11 arista **vec;
12 public:
13 grafoListaAd(int numVert);
14 bool existe_arista(int u, int v) const;
15 void insertar_arista(int u, int v, bool nueva=false);
16 void imprime(ostream &s) const;
17 };
18 grafoListaAd::grafoListaAd(int numVert) {
19 this->numVert = numVert;
20 vec = new arista*[numVert];
21 for (int i=0; i < numVert; i++) vec[i] = 0;
22 }
FI– UPV: Curso 2008/2009 P´gina 4.13
a
15. EDA-4
23 bool grafoListaAd::existe_arista(int u, int v) const {
24 for (const arista *r = vec[u]; r != 0; r = r->sig)
25 if (r->vertice_destino == v) return true;
26 return false;
27 }
28 void grafoListaAd::insertar_arista(int u, int v, bool nueva) {
29 if (nueva || !existe_arista(u,v))
30 vec[u] = new arista(v,vec[u]);
31 }
32 void grafoListaAd::imprime(ostream &s) const {
33 for (int i=0; i < numVert; i++) {
34 s << i << ":";
35 for (const arista *r = vec[i]; r != 0; r = r->sig) {
36 if (r != vec[i]) s << ",";
37 s << r->vertice_destino;
38 }
39 s << endl;
40 }
41 }
42 ostream& operator << (ostream& s, grafoListaAd &grafo) {
43 grafo.imprime(s); return s;
44 }
FI– UPV: Curso 2008/2009 P´gina 4.14
a
16. EDA-4
45 int main(int argc, char *argv[]) {
46 if (argc != 2) {
47 cerr << "Uso: " << argv[0] << " maxNodosn"; exit(0);
48 }
49 int numVert = atoi(argv[1]);
50 grafoListaAd list_ad(numVert);
51 int u,v;
52 while (cin >> u >> v) { // lectura de aristas
53 if (0 <= u && u < numVert && 0 <= v && v < numVert)
54 list_ad.insertar_arista(u, v);
55 }
56 // volcado por salida estandar
57 cout << "nListas de adyacencian" << list_ad << endl;
58 return 0;
59 }
FI– UPV: Curso 2008/2009 P´gina 4.15
a
17. EDA-4
Resumen: Representaci´n de grafos
o
Espacio
Matriz de adyacencia Θ(|V |2)
Listas de adyacencia Θ(|V | + |A|)
Construcci´n del grafo
o (u, v) ∈ A
Matriz de adyacencia Θ(|V |2) Θ(1)
Listas de adyacencia Θ(|V | + |A|) Θ(grado salida(u))
Recorrido sucesores Recorrido predecesores
Matriz de adyacencia Θ(|V |) Θ(|V |)
Listas de adyacencia Θ(grado salida(u)) Θ(|V | + |A|)
Listas de incidencia Θ(|V | + |A|) Θ(grado entrada(u))
FI– UPV: Curso 2008/2009 P´gina 4.16
a
18. EDA-4
Ejercicio: Grafo traspuesto
El grafo traspuesto de un grafo dirigido G = (V, A) es un grafo
Gt = (V, At) donde (u, v) ∈ At si y s´lo si (v, u) ∈ A. Escribe dos
o
algoritmos que permitan construir el grafo traspuesto Gt a partir
de G:
En el primer algoritmo los grafos se representar´n mediante
a
matrices de adyacencia.
En el segundo algoritmo los grafos se representar´n mediante
a
listas de adyacencia.
Calcula el coste computacional de los dos algoritmos.
FI– UPV: Curso 2008/2009 P´gina 4.17
a
19. EDA-4
Ejercicio: Grafo traspuesto
Se puede modificar el propio grafo:
1 void grafoDirigidoBitMat::trasponer () { // in place
2 for (int u=0; u < vertices; ++u)
3 for (int v=0; v < u; ++v) {
4 bool aux = vec[indice(u,v)];
5 vec[indice(u,v)] = vec[indice(v,u)];
6 vec[indice(v,u)] = aux;
7 }
8 }
Coste: Recorrer la matriz Θ(|V |2)
FI– UPV: Curso 2008/2009 P´gina 4.18
a
20. EDA-4
Ejercicio: Grafo traspuesto
O bien devolver otra instancia de la clase:
1 grafoListaAd* grafoListaAd::trasponer() const { // devuelve OTRO grafo
2 grafoListaAd* resul = new grafoListaAd(numVert);
3 for (int u=0; u < numVert; ++u)
4 for (const arista *r = vector[u]; r != 0; r = r->sig) {
5 int v = r->vertice_destino;
6 // le decimos true para no subir el coste innecesariamente:
7 resul->insertar_arista(v,u,true);
8 }
9 return resul;
10 }
Coste: Recorrer la matriz Θ(|V | + |A|)
FI– UPV: Curso 2008/2009 P´gina 4.19
a
21. EDA-4
Ejercicio: Cuadrado de un grafo
El cuadrado de un grafo dirigido G = (V, A) se define como
G2 = (V, A ) tal que (u, w) ∈ A si y solo si para alg´n v ∈ V se
u
cumple que (u, v) ∈ A y (v, w) ∈ A en el grafo G.
Escribe dos algoritmos para calcular G2 a partir de G, suponien-
do que este ultimo est´ representado como una matriz de
´ a
adyacencia y como lista de adyacencia.
Calcula el coste temporal de los algoritmos resultantes, justif-
ic´ndolo adecuadamente.
a
FI– UPV: Curso 2008/2009 P´gina 4.20
a
22. EDA-4
Ejercicio: Cuadrado de un grafo
Soluci´n con matriz de adyacencia:
o
1 grafoDirigidoBitMat* grafoDirigidoBitMat::cuadrado() const {
2 // devuelve otro grafo
3 grafoDirigidoBitMat *resul = new grafoDirigidoBitMat(numVert);
4 for (int u=0; u<numVert; ++u)
5 for (int v=0; v<numVert; ++v) {
6 bool camino=false;
7 for (int w=0; w<numVert && !camino; ++w)
8 camino = camino || (vec[indice(u,w)] && vec[indice(w,v)]);
9 resul->vec[indice(u,v)] = camino;
10 }
11 return resul;
12 }
|V | |V | |V |
Coste: u=1 v=1 w=1 1 ∈ O(|V |3)
FI– UPV: Curso 2008/2009 P´gina 4.21
a
23. EDA-4
Ejercicio: Cuadrado de un grafo
Soluci´n con listas de adyacencia:
o
1 grafoListaAd *grafoListaAd::cuadrado() const {
2 grafoListaAd *resul = new grafoListaAd(vertices);
3 for (int u=0; u<vertices; ++u)
4 for (const arista* r=vec[u]; r!=0; r=r->sig)
5 for (const arista* s=vec[r->vertice_destino]; s!=0; s=s->sig)
6 resul->insertar_arista(u, s->vertice_destino);
7 return resul;
8 }
FI– UPV: Curso 2008/2009 P´gina 4.22
a
24. EDA-4
´ ´
3. ARBOLES: DEFINICIONES BASICAS
Bosque: es un grafo no dirigido ac´ ıclico.
´
Arbol libre: es un grafo no dirigido ac´ ıclico conexo.
´
Arbol de recubrimiento de un grafo no dirigido G = (V, A): es un ´rbol libre
a
T = (V , A ) tal que V = V y A ⊆ A.
Grafo Bosque Arbol
FI– UPV: Curso 2008/2009 P´gina 4.23
a
25. EDA-4
´ ´
3. ARBOLES: DEFINICIONES BASICAS
Teorema (Propiedades de los ´rboles libres):
a
Sea G = (V, A) un grafo no dirigido. Los siquientes predicados son equivalentes:
1. G es un ´rbol libre.
a
2. Cualquier par de v´rtices est´ conectados por un unico camino.
e a ´
3. G es conexo, pero si se elimina cualquier arista de A, el grafo resultante
no es conexo.
4. G es conexo y tiene |V | − 1 aristas.
ıclico, y tiene |V | − 1 aristas.
5. G es ac´
6. G es ac´
ıclico, pero si se a˜ade una arista, se crea un ciclo.
n
Arbol
FI– UPV: Curso 2008/2009 P´gina 4.24
a
26. EDA-4
´ ´
3. ARBOLES: DEFINICIONES BASICAS
´
Arbol enraizado
Un ´rbol enraizado es un ´rbol libre con un v´rtice (o nodo) distinguido denominado ra´
a a e ız.
raíz 7
3 10 4
8 12 11 2
6 5 1
9
Si existe un camino de un nodo x a un nodo y en un ´rbol T , se dice que x es antecesor
a
de y, y que y es sucesor de x.
Si (x, y) es el ultimo arco en el camino desde la ra´ r del ´rbol T hasta el nodo y,
´ ız a
entonces x es el padre de y, e y es el hijo de x. La ra´ es el unico nodo en T que no
ız ´
tiene padre. Si dos nodos tienen el mismo padre son hermanos.
FI– UPV: Curso 2008/2009 P´gina 4.25
a
27. EDA-4
´ ´
3. ARBOLES: DEFINICIONES BASICAS
´
Arbol enraizado
Un nodo sin hijos lo denominaremos hoja. El resto son nodos internos.
El grado de un nodo es el n´mero de hijos que tiene.
u
Se llama profundidad de un nodo a la longitud del camino desde la ra´ a ese nodo.
ız
La altura de un ´rbol es la profundidad del nodo m´s profundo.
a a
7 profundidad 0
3 10 4 profundidad 1
altura=4 8 12 11 2 profundidad 2
6 5 1 profundidad 3
9 profundidad 4
FI– UPV: Curso 2008/2009 P´gina 4.26
a
28. EDA-4
´
4. ARBOLES BINARIOS
Un ´rbol binario es un ´rbol en el que el m´ximo n´mero de hijos de cada
a a a u
nodo es 2 (hijo izquierdo e hijo derecho).
3
profundidad 0
2 7
profundidad 1
4 1 5 altura=3
profundidad 2
6 profundidad 3
Un ´rbol binario se dice que es completo (o lleno) si todas las hojas tienen
a
la misma profundidad y todos los nodos internos tienen grado 2.
Un ´rbol binario es casi-completo si el ´rbol es completo, a excepci´n quiz´s
a a o a
en el nivel de las hojas, en el cual todas las hojas est´n tan a la izquierda
a
como sea posible.
FI– UPV: Curso 2008/2009 P´gina 4.27
a
29. EDA-4
Propiedades de los ´rboles binarios completos
a
profundidad num. nodos
0 1=2_0
1 2=2_1
h=3
2 4=2_2
3 8=2_3
´
Arbol binario completo de altura h = 3, con 8 hojas y 7 nodos internos
N´mero de nodos: La ra´ tiene 2 hijos de profundidad 1, cada uno de los cuales tienen 2
u ız
hijos de profundidad 2, etc. → Nodos de profundidad i = 2i.
h−1
hojas: 2h y nodos internos: 20 + 21 + · · · + 2h−1 = i=0 2i = 2h − 1
h i
nodos total: n = i=0 2 = 2h+1 − 1
. . . y la altura
n = 2h+1 − 1 → h = log2 n
FI– UPV: Curso 2008/2009 P´gina 4.28
a
30. EDA-4
Propiedades de los ´rboles binarios
a
El m´ximo n´mero de nodos de profundidad i es 2i.
a u
El m´ximo n´mero de nodos en un ´rbol binario de altura h es
a u a
2h+1 − 1. El m´ximo n´mero de nodos internos es 2h − 1. El m´ximo
a u a
n´mero de hojas es 2h.
u
La altura m´ınima de un ´rbol binario con n nodos es log2 n .
a
Para cualquier ´rbol binario no vac´ si n0 es el n´mero de hojas y
a ıo, u
n2 es el n´mero de nodos de grado 2, entonces n0 = n2 + 1.
u
´
Ejercicio. Arboles k-arios. Un ´rbol k-ario es un ´rbol en el que el
a a
m´ximo n´mero de hijos de cada nodo es k (as´ un ´rbol binario es un
a u ı, a
´rbol k-ario con k = 2). ¿Cu´ntas hojas tiene un ´rbol k-ario completo
a a a
de altura h? ¿Y cu´ntos nodos internos?
a
FI– UPV: Curso 2008/2009 P´gina 4.29
a
31. EDA-4
´ ´
5. REPRESENTACION DE ARBOLES
´
Arboles (n´mero de hijos sin acotar)
u
• Listas (ordenadas) de hijos.
• Hijo m´s a la izquierda-Hermano derecha: variables din´micas
a a
o vectores.
• Con vectores y direcci´n del padre.
o
• Otros . . .
´
Arboles binarios
• Hijo izquierdo e Hijo derecho para cada nodo: variables
din´micas o vectores.
a
´
• Arbol binario (casi-completo): vector (“heaps”).
• Otros . . .
FI– UPV: Curso 2008/2009 P´gina 4.30
a
33. EDA-4
´ ´
5. REPRESENTACION DE ARBOLES
Hijo m´s a la izquierda-Hermano derecha: variables din´micas o vectores
a a
clave
hizq her_d
2 3 C 10
3 17 D 9
raíz 4 8 A NIL
raíz
....
8 NIL B 2 A
9 NIL H NIL
10 13 I NIL
B C I
A ....
12 NIL G NIL
13 14 J NIL
D H J
B C I
14 NIL K 16
15 NIL F 12 E F G K L
D H J 16 NIL L 7
17 NIL E 15 clave
E F G K L .... hizq her_d
FI– UPV: Curso 2008/2009 P´gina 4.32
a
34. EDA-4
´ ´
5. REPRESENTACION DE ARBOLES
Con vectores y direcci´n del padre
o
3 3
2 1 9 2 1 9
4 8 10 4 8 10
5 6 7 11 12 5 6 7 11 12
1 2 3 4 5 6 7 8 9 10 11 12
3 3 3 1 4 4 4 1 3 9 10 10
El nodo i es la ra´ del ´rbol si T [i] = i. Cada nodo apunta a su
ız a
padre: T [i] = padre(i).
FI– UPV: Curso 2008/2009 P´gina 4.33
a
35. EDA-4
´ ´
5. REPRESENTACION DE ARBOLES
´
Arboles binarios: variables din´micas o vectores
a
(opcionalmente, puntero al padre)
clave
hizq hder
2 15 A NIL
3 NIL D NIL raíz
raíz 4 8 C 12
.... C
8 3 B 2
9
C 10
B G
....
12 17 G NIL
B G D A E
13
14
D A E 15 NIL F NIL F
16
17 NIL E NIL clave
F .... hizq hder
FI– UPV: Curso 2008/2009 P´gina 4.34
a
36. EDA-4
´ ´
5. REPRESENTACION DE ARBOLES
´
Arboles binarios (casi-completos): vector
1
A
raiz: T[1]
padre[i]=[i/2] 2 3
B C
hizquierdo[i]=2i
hderecho[i]=2i+1 6 7
4 5
D E F G
8 9 10 11 12
H I J K L
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ...
A B C D E F G H I J K L
padre hizquierdo
raíz hderecho talla=12
FI– UPV: Curso 2008/2009 P´gina 4.35
a
37. EDA-4
´
6. RECORRIDOS DE ARBOLES BINARIOS
A veces puede interesar un recorrido sistem´tico y eficiente de todos los nodos del ´rbol.
a a
A
B C Recorrido en preorden: ABDEHJICFG
Recorrido en inorden: DBHJEIAFGC
D E F
Recorrido en postorden: DJHIEBGFCA
H I G
Recorrido en niveles: ABCDEFHIGJ
J
Coste de todos los algoritmos Θ(n), siendo n el n´mero de nodos del ´rbol → despu´s de la
u a e
llamada inicial, la funci´n se llama recursivamente exactamente 2 veces para cada nodo del
o
´rbol: una vez para su hijo izquierdo y otra para su hijo derecho.
a
FI– UPV: Curso 2008/2009 P´gina 4.36
a
38. EDA-4
6. Recorridos de ´rboles binarios: PREORDEN
a
La clave de la ra´ se imprime antes de los valores de sus sub´rboles
ız a
A
B C
D E F
H I G
J
9 void nodo_abb::preorden() {
10 cout << valor << endl;
11 if (h_izq != 0) h_izq->preorden();
12 if (h_der != 0) h_der->preorden();
13 }
FI– UPV: Curso 2008/2009 P´gina 4.37
a
39. EDA-4
6. Recorridos de ´rboles binarios: INORDEN
a
La clave de la ra´ se imprime entre los valores de su sub´rbol izquierdo y derecho
ız a
A
B C
D E F
H I G
J
14 void nodo_abb::inorden() {
15 if (h_izq != 0) h_izq->inorden();
16 cout << valor << endl;
17 if (h_der != 0) h_der->inorden();
18 }
FI– UPV: Curso 2008/2009 P´gina 4.38
a
40. EDA-4
6. Recorridos de ´rboles binarios: POSTORDEN
a
La clave de la ra´ se imprime despu´s de los valores de sus sub´rboles
ız e a
A
B C
D E F
H I G
J
19 void nodo_abb::postorden() {
20 if (h_izq != 0) h_izq->postorden();
21 if (h_der != 0) h_der->postorden();
22 cout << valor << endl;
23 }
FI– UPV: Curso 2008/2009 P´gina 4.39
a
41. EDA-4
6. Recorridos de ´rboles binarios: NIVELES
a
En lugar de una pila (recursi´n) se utiliza una cola.
o
24 void abb::por_niveles() {
25 cola *c = new cola(); // una cola de nodo_abb*
26 nodo_abb *n;
27 c->insertar(raiz);
28 while (c->extraer(n)) {
29 if (n != 0) { // se puede poner if (n) {
30 cout << n->valor << endl;
31 c->insertar(n->h_izq);
32 c->insertar(n->h_der);
33 }
34 }
35 delete c;
36 }
FI– UPV: Curso 2008/2009 P´gina 4.40
a
42. EDA-4
Ejemplo ´rboles binarios: ´rbol de expresiones
a a
Utilizaci´n de la estructura AB para representar expresiones aritm´ticas con operadores
o e
binarios.
ra´ operador principal
ız:
nodos internos: operadores de subexpresiones
hojas: operandos
(niveles: precedencia relativa de evaluaci´n)
o
x Recorrido en preorden: × + / a b c − d e
notaci´n prefija o polaca
o
+ - Recorrido en inorden: (((a/b) + c) × (d − e))
notaci´n infija
o
/ c d e Recorrido en postorden: a b / c + d e − ×
notaci´n postfija o polaca inversa
o
a b
FI– UPV: Curso 2008/2009 P´gina 4.41
a
43. EDA-4
7. RECORRIDOS DE GRAFOS
M´todo para recorrer de forma sistem´tica y eficiente un grafo.
e a
Recorrido en profundidad: generalizaci´n del recorrido en preorden de
o
un ´rbol
a
Recorrido en amplitud: generalizaci´n del recorrido en niveles de un
o
´rbol
a
En todos los algoritmos de recorrido de grafos supondremos que el grafo
est´ implementado con listas de adyacencia.
a
FI– UPV: Curso 2008/2009 P´gina 4.42
a
44. EDA-4
Recorrido en profundidad de un grafo
Dado un grafo G = (V, A) y un v´rtice v ∈ V , la estrategia de recorrido
e
en profundidad (Depth-First Search (DFS)), explora sistem´ticamente
a
las aristas de G de manera que primero se visitan los v´rtices adyacentes
e
a los visitados m´s recientemente. De esta forma, se va profundizando
a
en el grafo; es decir, alej´ndose progresivamente de v.
a
Este proceso continua hasta que todos los v´rtices alcanzables desde el
e
v´rtice de la llamada original han sido descubiertos.
e
Esta estrategia admite una implementaci´n simple de forma recursiva y
o
proporciona:
Ordenamientos de los v´rtices.
e
Clasificaci´n de las aristas.
o
Algunas aplicaciones:
Calcular un posible orden topol´gico y comprobar si el grafo es ac´
o ıclico.
Encontrar las componentes fuertemente conexas de un grafo.
FI– UPV: Curso 2008/2009 P´gina 4.43
a
45. EDA-4
Recorrido en profundidad de un grafo
El algoritmo DFS asocia los siguientes datos a cada v´rtice v del grafo:
e
d[v] ⇒ instante en que el v´rtice v es descubierto
e
f[v] ⇒ instante en que finaliza la exploraci´n del v´rtice v
o e
pr[v] ⇒ el v´rtice predecesor de v en el ´rbol generado (´rbol de
e a a
exploraci´n primero en profundidad, es un subgrafo del grafo original).
o
El color asociado al v´rtice, que puede ser de 3 tipos:
e
• WHITE ⇒ cuando nunca ha sido explorado,
• GRAY ⇒ mientras est´ siendo explorado,
a
• BLACK ⇒ cuando ya ha sido explorado.
Al principio todos los v´rtices se ponen de color WHITE. Se utiliza un
e
atributo time como contador para marcar los instantes.
FI– UPV: Curso 2008/2009 P´gina 4.44
a
46. EDA-4
Recorrido en profundidad de un grafo
1 void grafo::dfs_visit(int u) {// algoritmo recursivo del DFS
2 color[u] = GRAY;
3 d[u] = ++time;
4 for (arista *r = vec[u]; r != 0; r = r->sig) {
5 int v = r->vertice_destino;
6 if (color[v] == WHITE) { pr[v] = u;
7 dfs_visit(v); }
8 }
9 color[u] = BLACK;
10 f[u] = ++time;
11 }
12 void grafo::dfs() {
13 for (int u=0; u < numVert; ++u) { color[u] = WHITE;
14 pr[u] = -1; }
15 time = 0;
16 for (int u=0; u < numVert; ++u)
17 if (color[u] == WHITE) dfs_visit(u);
18 }
Coste Θ(|V | + |A|)
FI– UPV: Curso 2008/2009 P´gina 4.45
a
48. EDA-4
Recorrido en profundidad de un grafo: Ejemplo
dfs_visit(0)
(0,4) is a TREE EDGE
dfs_visit(4)
(0,3) is a TREE EDGE
dfs_visit(3)
(3,4) is a FORWARD/CROSS EDGE
(3,1) is a TREE EDGE
dfs_visit(1)
(1,4) is a FORWARD/CROSS EDGE
(0,2) is a TREE EDGE
dfs_visit(2)
(2,3) is a FORWARD/CROSS EDGE
(0,1) is a FORWARD/CROSS EDGE
dfs_visit(5)
(5,7) is a TREE EDGE
dfs_visit(7)
(7,5) is a BACK EDGE
(5,6) is a TREE EDGE
dfs_visit(6)
(6,7) is a FORWARD/CROSS EDGE
FI– UPV: Curso 2008/2009 P´gina 4.47
a
50. EDA-4
Recorrido en profundidad de un grafo
Clasificaci´n de las aristas. Una arista (u, v) es de tipo:
o
TREE o del ´rbol: si el v´rtice v ha sido descubierto a trav´s de
a e e
dicha arista. Estas aristas definen el bosque del recorrido primero en
profundidad, formado por uno o m´s ´rboles.
a a
BACK o hacia atr´s: si v es un antecesor de u en el ´rbol del recorrido
a a
primero en profundidad.
FORWARD o hacia adelante: si v es un descendiente de u en el ´rbola
del recorrido primero en profundidad.
CROSS o de cruce: ning´n v´rtice es antecesor del otro.
u e
El recorrido DFS puede ser utilizado para clasificar las aristas a medida
que las va procesando. Cuando desde un v´rtice u se considera la arista
e
(u, v), se puede observar el color del v´rtice destino v:
e
WHITE indica que es una arista del ´rbol o TREE.
a
GRAY indica que es una arista hacia atr´s o BACK.
a
BLACK indica que es hacia delante o de cruce. Si d[u] < d[v] es hacia
delante y si d[u] > d[v] es de cruce.
FI– UPV: Curso 2008/2009 P´gina 4.49
a
51. EDA-4
Recorrido en profundidad de un grafo
Relaci´n de tipo “par´ntesis”: en la b´squeda primero en profundidad,
o e u
dados dos v´rtices del grafo u y v, se cumple exactamente una de estas
e
tres posibilidades:
los intervalos [d[u], f [u]] y [d[v], f [v]] son enteramente disjuntos. En
este caso, ni u es descendiente de v en el ´rbol DFS ni v descendiente
a
de u.
el intervalo [d[u], f [u]] est´ contenido enteramente dentro del inter-
a
valor [d[v], f [v]] y u es descendiente de v en el ´rbol DFS.
a
el intervalo [d[v], f [v]] est´ contenido enteramente dentro del intervalor
a
[d[u], f [u]] y v es descendiente de u en el ´rbol DFS.
a
La relaci´n de estos intervalos tambi´n sirve para clasificar las aristas,
o e
as´ la arista (u, v) es:
ı
del ´rbol si d[u] < d[v] < f [v] < f [u]
a
hacia atr´s si d[v] < d[u] < f [u] < f [v]
a
de cruce si d[v] < f [v] < d[u] < f [u]
FI– UPV: Curso 2008/2009 P´gina 4.50
a
52. EDA-4
Orden topol´gico
o
Un orden topol´gico de un grafo dirigido ac´
o ıclico G = (V, A) es una
ordenaci´n de los v´rtices de forma que si (u, v) ∈ A, entonces u aparece
o e
antes que v. (La soluci´n no es unica.) Ejem.: prerrequisitos de los
o ´
estudios.
¡No es posible la ordenaci´n topol´gica cuando existen ciclos!
o o
a b d a e b c
c
d e
a b d e c
Orden no unico.
´
Ordenaci´n de v´rtices en eje horizontal con las aristas de izquierda a derecha.
o e
FI– UPV: Curso 2008/2009 P´gina 4.51
a
53. EDA-4
Orden topol´gico
o
Dado un grafo G = (V, A), el DFS puede usarse para determinar si es
ac´
ıclico y, en ese caso, obtener un orden topol´gico.
o
El grafo es ac´ıclico si no tiene ninguna arista hacia atr´s.
a
El orden en que finaliza la exploraci´n de los v´rtices (valor guardado
o e
en f [v]) es un orden topol´gico invertido.
o
1 void grafo::dfs_visit(int u) {
2 color[u] = GRAY;
3 d[u] = ++time;
4 for (arista *r = vec[u]; r != 0; r = r->sig) {
5 int v = r->vertice_destino;
6 if (color[v] == WHITE) { pr[v] = u;
7 dfs_visit(v);
8 } else if (color[v] == GRAY) es_aciclico = false;
9 } // es_aciclico esta a true antes de empezar DFS
10 color[u] = BLACK;
11 f[u] = time;
12 topologic_sort.push_front(u); // insertar al ppio
13 }
FI– UPV: Curso 2008/2009 P´gina 4.52
a
54. EDA-4
Recorrido en profundidad de un grafo: Ejemplo 2
dfs_visit(0)
Grafo: (0,2) is a TREE EDGE
dfs_visit(2)
11 (2,4) is a TREE EDGE
0 1 dfs_visit(4)
(4,7) is a TREE EDGE
0 2 dfs_visit(7)
1 3 (4,6) is a TREE EDGE
dfs_visit(6)
2 4 (0,1) is a TREE EDGE
3 2 dfs_visit(1)
(1,9) is a TREE EDGE
3 4 dfs_visit(9)
3 5 (9,10) is a TREE EDGE
5 7 dfs_visit(10)
(1,8) is a TREE EDGE
4 6 dfs_visit(8)
4 7 (8,10) is a FORWARD/CROSS EDGE
(1,3) is a TREE EDGE
1 8 dfs_visit(3)
1 9 (3,5) is a TREE EDGE
dfs_visit(5)
8 10 (5,7) is a FORWARD/CROSS EDGE
9 10 (3,4) is a FORWARD/CROSS EDGE
(3,2) is a FORWARD/CROSS EDGE
FI– UPV: Curso 2008/2009 P´gina 4.53
a
55. EDA-4
Recorrido en profundidad de un grafo: Ejemplo 2
v d[v] f[v] pr[v]
0 1 22 -1
1 10 21 0
2 2 9 0
3 17 20 1
4 3 8 2
5 18 19 3
6 6 7 4
7 4 5 4
8 15 16 1
9 11 14 1
10 12 13 9
Un posible orden topologico: 0 1 3 5 8 9 10 2 4 6 7
FI– UPV: Curso 2008/2009 P´gina 4.54
a
56. EDA-4
Otro algoritmo para el orden topol´gico, sin DFS
o
1 void grafo::orden_topologico_sin_dfs() { // test aciclicidad
2 int u,v; arista *r;
3 for (v=0; v < numVert; ++v) grado_entrada[v] = 0;
4 for (v=0; v < numVert; ++v)
5 for (r = vec[v]; r != 0; r = r->sig)
6 grado_entrada[r->vertice_destino]++;
7 col->vaciar();
8 for (v=0; v < numVert; v++)
9 if (grado_entrada[v] == 0) col->insertar(v);
10 for (n = 0; col->extraer(u); n++) {
11 topologic_sort.push_back(u); // insertar al final
12 for (arista *r = vec[u]; r != 0; r = r->sig) {
13 grado_entrada[r->vertice_destino]--;
14 if (grado_entrada[r->vertice_destino] == 0)
15 col->insertar(r->vertice_destino);
16 }
17 }
18 es_aciclico = (n == numVert);
19 }
FI– UPV: Curso 2008/2009 P´gina 4.55
a
57. EDA-4
Recorrido en amplitud de un grafo
Dado un grafo G = (V, A) y un v´rtice s ∈ V , la estrategia de
e
recorrido en amplitud o en anchura (Breadth-First Search (BFS)),
explora sistem´ticamente las aristas de G de manera que primero se
a
visitan los v´rtices m´s cercanos a v.
e a
Algunos algoritmos importantes de grafos tienen una estructura similar
al BFS. Por ejemplo, el algoritmo de Prim para encontrar el ´rbol de
a
expansi´n de m´
o ınimo coste, o el algoritmo de Dijkstra para encontrar
los caminos m´s cortos desde un v´rtice dado.
a e
El algoritmo BFS explora todos los v´rtices a distancia k del v´rtice
e e
origen s antes de empezar a explorar los v´rtices a distancia k + 1.
e
Al igual que DFS, se utiliza un vector de tipo “color” para marcar los
v´rtices del grafo como no visitados (WHITE), visit´ndose (GRAY) o
e a
ya visitados (BLACK).
Tambi´n se genera un vector de predecesores para obtener un ´rbol.
e a
FI– UPV: Curso 2008/2009 P´gina 4.56
a
58. EDA-4
Recorrido en amplitud de un grafo
1 void grafo::bfs(int vertice) {
2 cola.clear();
3 for (int u=0; u < numVert; ++u) {
4 color[u]=WHITE; pr[u]=-1; d[u]=numVert+1;
5 // numVert+1> cualquier distancia en el grafo
6 }
7 cola.push_back(vertice);
8 d[vertice] = 0;
9 while (!cola.empty()) {
10 int u = cola.front(); cola.pop_front(); // extraer
11 for (arista *r = vec[u]; r != 0; r = r->sig) {
12 int v = r->vertice_destino;
13 if (color[v] == WHITE) {
14 color[v]=GRAY; d[v]=d[u]+1; pr[v]=u;
15 cola.push_back(v);
16 }
17 }
18 color[u] = BLACK;
19 }
20 }
FI– UPV: Curso 2008/2009 P´gina 4.57
a