Está en la página 1de 60

Estructuras de Datos y Algoritmos

Facultad de Informatica
Universidad Politecnica de Valencia
Curso 2008/2009
Tema 4:
Grafos y arboles
FI UPV: Curso 2008/2009
EDA-4
TEMA 4. Grafos y arboles
Objetivos
Deniciones, representacion y recorrido de arboles y grafos.
Contenidos
1 Grafos: Deniciones basicas
2 Representacion de grafos
3

Arboles: Deniciones basicas
4

Arboles binarios
5 Representacion de arboles
6 Recorridos de arboles binarios
7 Recorrido de grafos
8 Orden topologico en grafos acclicos
Bibliografa
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 (captulos 3, 6 y 7)
FI UPV: Curso 2008/2009 Pagina 4.1
EDA-4
1. GRAFOS: DEFINICIONES B

ASICAS
Grafo dirigido: es un par G = (V, A) donde V es un conjunto nito de elementos
llamados vertices y A V V es un conjunto de pares ordenados de vertices llamados
aristas.
Si (u, v) es una arista de G, se dice que el vertice v es adyacente a u.
0 1 2
5 3 4
FI UPV: Curso 2008/2009 Pagina 4.2
EDA-4
1. GRAFOS: DEFINICIONES B

ASICAS
Grafo no dirigido: es un par G = (V, A) donde V es un conjunto nito de vertices y
A u, v [ u, v V v ,= u es un conjunto de pares no ordenados de vertices.
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 vertice v es adyacente a u. La relacion es
simetrica.
0 1
4 3
2
FI UPV: Curso 2008/2009 Pagina 4.3
EDA-4
1. GRAFOS: DEFINICIONES B

ASICAS
Grado: para todo vertice v,
grado de entrada es el n umero de aristas que inciden en v;
grado de salida es el n umero de aristas que emergen de v;
grado es la suma de los grados de entrada y salida de v.
El grado de un grafo es el maximo grado de sus vertices.
0 1 2
5 3 4
Ejem.: El grado de entrada del vertice 1 es 2; el grado de salida es 1; el grado del vertice es 3. El grado del
grafo es 3.
FI UPV: Curso 2008/2009 Pagina 4.4
EDA-4
1. GRAFOS: DEFINICIONES B

ASICAS
Camino desde un vertice u V a un vertice v V : es una secuencia v
0
, v
1
, . . . , v
k
) de
vertices de G = (V, A) tal que v
0
= u, v
k
= v, (v
i
, v
i+1
) A, 0 i < k.
La longitud de un camino v
0
, v
1
, . . . , v
k
) es el n umero de aristas que lo forman.
Camino simple: es un camino v
0
, v
1
, . . . , v
k
) en el que todos sus vertices son distintos,
excepto quizas el primero y el ultimo.
Ciclo: es un camino simple v
0
, v
1
, . . . , v
k
) tal que v
0
= v
k
y el camino contiene al menos
una arista.
Un bucle es un ciclo de longitud 1.
0 1 2
5 3 4
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 acclico: es un grafo sin ciclos.
FI UPV: Curso 2008/2009 Pagina 4.5
EDA-4
1. GRAFOS: DEFINICIONES B

ASICAS
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
5 3 4
0 1
3 4
0 1
3 4
Subgrafo Subgrafo inducido por V

= 0, 1, 3, 4
FI UPV: Curso 2008/2009 Pagina 4.6
EDA-4
1. GRAFOS: DEFINICIONES B

ASICAS
Vertice alcanzable desde un vertice u: es cualquier vertice v para el que existe un
camino de u a v.
Las componentes conexas en un grafo no dirigido son las clases de equivalencia de
vertices seg un la relacion ser alcanzable.
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 vertices seg un la relacion ser mutuamente alcanzable.
Un grafo dirigido es fuertemente conexo si u, v V , v es alcanzable desde u.
0 1
4 3
2
0 1 2
5 3 4
FI UPV: Curso 2008/2009 Pagina 4.7
EDA-4
1. GRAFOS: DEFINICIONES B

ASICAS
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 nado de una funcion f : A E,
donde E es un conjunto cuyas componentes se denominan etiquetas.
Grafo ponderado: es un grafo etiquetado con n umeros reales (E R).
Un grafo se considera denso si [A[ [V [
2
.
Un grafo se considera disperso si [A[ <<< [V [
2
.
FI UPV: Curso 2008/2009 Pagina 4.8
EDA-4
2. REPRESENTACI

ON 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 1 2
5 3 4
0
0
0
0
0
0
1 0 1 0 0
0
0
1
0
0
0
0
0
0
0
0
0
0
1
0
1
1
0
0
0
0
1
0
1
0
0
1
2
3
4
5
0 1
4 3
2
1 0 0 1
0
1
1
1
1
0
1
0
1
1
0
1
1
0
1
0
0
1
2
3
4
0
1
0
0
1
FI UPV: Curso 2008/2009 Pagina 4.9
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 Pagina 4.10
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] << " maxNodos\n"; 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 adyacencia\n" << gdmat << endl;
38 return 0;
39 }
FI UPV: Curso 2008/2009 Pagina 4.11
EDA-4
2. REPRESENTACI

ON DE GRAFOS: Listas de adyacencia


Un grafo G = (V, A) se representa como un vector de listas de vertices indexado por vertices;
es decir, G: vector[V ] de V . Cada componente G[v] es una lista de los vertices emergentes
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 2
5 3 4
0
1
2
3
4
5
4 5
NIL
1
NIL
3
NIL
5
NIL
4
NIL
1 3
NIL
0 1
4 3
2
0
1
2
3
4
3 1
NIL
0
1 4
NIL
4 3 2
NIL
3 0 1
NIL
4 2 1
NIL
FI UPV: Curso 2008/2009 Pagina 4.12
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 Pagina 4.13
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 Pagina 4.14
EDA-4
45 int main(int argc, char
*
argv[]) {
46 if (argc != 2) {
47 cerr << "Uso: " << argv[0] << " maxNodos\n"; 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 adyacencia\n" << list_ad << endl;
58 return 0;
59 }
FI UPV: Curso 2008/2009 Pagina 4.15
EDA-4
Resumen: Representacion de grafos
Espacio
Matriz de adyacencia ([V [
2
)
Listas de adyacencia ([V [ +[A[)
Construccion del grafo (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 Pagina 4.16
EDA-4
Ejercicio: Grafo traspuesto
El grafo traspuesto de un grafo dirigido G = (V, A) es un grafo
G
t
= (V, A
t
) donde (u, v) A
t
si y solo si (v, u) A. Escribe dos
algoritmos que permitan construir el grafo traspuesto G
t
a partir
de G:
En el primer algoritmo los grafos se representaran mediante
matrices de adyacencia.
En el segundo algoritmo los grafos se representaran mediante
listas de adyacencia.
Calcula el coste computacional de los dos algoritmos.
FI UPV: Curso 2008/2009 Pagina 4.17
EDA-4
Ejercicio: Grafo traspuesto
Se puede modicar 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 Pagina 4.18
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 Pagina 4.19
EDA-4
Ejercicio: Cuadrado de un grafo
El cuadrado de un grafo dirigido G = (V, A) se dene como
G
2
= (V, A

) tal que (u, w) A

si y solo si para alg un v V se


cumple que (u, v) A y (v, w) A en el grafo G.
Escribe dos algoritmos para calcular G
2
a partir de G, suponien-
do que este ultimo esta representado como una matriz de
adyacencia y como lista de adyacencia.
Calcula el coste temporal de los algoritmos resultantes, justif-
icandolo adecuadamente.
FI UPV: Curso 2008/2009 Pagina 4.20
EDA-4
Ejercicio: Cuadrado de un grafo
Solucion con matriz de adyacencia:
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 }
Coste:

|V |
u=1

|V |
v=1

|V |
w=1
1 O([V [
3
)
FI UPV: Curso 2008/2009 Pagina 4.21
EDA-4
Ejercicio: Cuadrado de un grafo
Solucion con listas de adyacencia:
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 Pagina 4.22
EDA-4
3.

ARBOLES: DEFINICIONES B

ASICAS
Bosque: es un grafo no dirigido acclico.

Arbol libre: es un grafo no dirigido acclico conexo.

Arbol de recubrimiento de un grafo no dirigido G = (V, A): es un arbol libre


T = (V

, A

) tal que V

= V y A

A.
Grafo Bosque Arbol
FI UPV: Curso 2008/2009 Pagina 4.23
EDA-4
3.

ARBOLES: DEFINICIONES B

ASICAS
Teorema (Propiedades de los arboles libres):
Sea G = (V, A) un grafo no dirigido. Los siquientes predicados son equivalentes:
1. G es un arbol libre.
2. Cualquier par de vertices esta conectados por un unico camino.
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.
5. G es acclico, y tiene [V [ 1 aristas.
6. G es acclico, pero si se a nade una arista, se crea un ciclo.
Arbol
FI UPV: Curso 2008/2009 Pagina 4.24
EDA-4
3.

ARBOLES: DEFINICIONES B

ASICAS

Arbol enraizado
Un arbol enraizado es un arbol libre con un vertice (o nodo) distinguido denominado raz.
7
3
8 12
10 4
11 2
5 6 1
9
raz
Si existe un camino de un nodo x a un nodo y en un arbol T, se dice que x es antecesor
de y, y que y es sucesor de x.
Si (x, y) es el ultimo arco en el camino desde la raz r del arbol T hasta el nodo y,
entonces x es el padre de y, e y es el hijo de x. La raz es el unico nodo en T que no
tiene padre. Si dos nodos tienen el mismo padre son hermanos.
FI UPV: Curso 2008/2009 Pagina 4.25
EDA-4
3.

ARBOLES: DEFINICIONES B

ASICAS

Arbol enraizado
Un nodo sin hijos lo denominaremos hoja. El resto son nodos internos.
El grado de un nodo es el n umero de hijos que tiene.
Se llama profundidad de un nodo a la longitud del camino desde la raz a ese nodo.
La altura de un arbol es la profundidad del nodo mas profundo.
7
3
8 12
10 4
11 2
5 6 1
9
profundidad 0
profundidad 1
profundidad 2
profundidad 3
profundidad 4
altura=4
FI UPV: Curso 2008/2009 Pagina 4.26
EDA-4
4.

ARBOLES BINARIOS
Un arbol binario es un arbol en el que el maximo n umero de hijos de cada
nodo es 2 (hijo izquierdo e hijo derecho).
3
2
4 1
7
5
6
profundidad 0
profundidad 1
profundidad 2
profundidad 3
altura=3
Un arbol binario se dice que es completo (o lleno) si todas las hojas tienen
la misma profundidad y todos los nodos internos tienen grado 2.
Un arbol binario es casi-completo si el arbol es completo, a excepcion quizas
en el nivel de las hojas, en el cual todas las hojas estan tan a la izquierda
como sea posible.
FI UPV: Curso 2008/2009 Pagina 4.27
EDA-4
Propiedades de los arboles binarios completos
0
1
2
3
h=3
1=2_0
2=2_1
4=2_2
8=2_3
profundidad num. nodos

Arbol binario completo de altura h = 3, con 8 hojas y 7 nodos internos


N umero de nodos: La raz tiene 2 hijos de profundidad 1, cada uno de los cuales tienen 2
hijos de profundidad 2, etc. Nodos de profundidad i = 2
i
.
hojas: 2
h
y nodos internos: 2
0
+ 2
1
+ + 2
h1
=

h1
i=0
2
i
= 2
h
1
nodos total: n =

h
i=0
2
i
= 2
h+1
1
. . . y la altura
n = 2
h+1
1 h = log
2
n|
FI UPV: Curso 2008/2009 Pagina 4.28
EDA-4
Propiedades de los arboles binarios
El maximo n umero de nodos de profundidad i es 2
i
.
El maximo n umero de nodos en un arbol binario de altura h es
2
h+1
1. El maximo n umero de nodos internos es 2
h
1. El maximo
n umero de hojas es 2
h
.
La altura mnima de un arbol binario con n nodos es log
2
n|.
Para cualquier arbol binario no vaco, si n
0
es el n umero de hojas y
n
2
es el n umero de nodos de grado 2, entonces n
0
= n
2
+ 1.
Ejercicio.

Arboles k-arios. Un arbol k-ario es un arbol en el que el
maximo n umero de hijos de cada nodo es k (as, un arbol binario es un
arbol k-ario con k = 2). Cuantas hojas tiene un arbol k-ario completo
de altura h? Y cuantos nodos internos?
FI UPV: Curso 2008/2009 Pagina 4.29
EDA-4
5. REPRESENTACI

ON DE

ARBOLES

Arboles (n umero de hijos sin acotar)


Listas (ordenadas) de hijos.
Hijo mas a la izquierda-Hermano derecha: variables dinamicas
o vectores.
Con vectores y direccion del padre.
Otros . . .

Arboles binarios
Hijo izquierdo e Hijo derecho para cada nodo: variables
dinamicas o vectores.


Arbol binario (casi-completo): vector (heaps).
Otros . . .
FI UPV: Curso 2008/2009 Pagina 4.30
EDA-4
5. REPRESENTACI

ON DE

ARBOLES
Listas (ordenadas) de hijos
1
3
10
5 6 7 11 12
2 9
4 8
1
2
3
4
5
6
7
10
8
9
10
11
12
NIL
5 6
NIL
7
NIL
11 12
NIL
NIL
NIL
NIL
NIL
NIL
NIL
2 3
NIL
9
4 8
NIL
raz
FI UPV: Curso 2008/2009 Pagina 4.31
EDA-4
5. REPRESENTACI

ON DE

ARBOLES
Hijo mas a la izquierda-Hermano derecha: variables dinamicas o vectores
B I
D H
A
C
J
E F G K L
2
3
4
....
8
9
10
....
12
13
14
16
17
....
15
K
F
L
E
16
12
7
15
3
17
8
NIL
NIL
13
NIL
14
C
D
A
H
I
G
J
10
9
2 B
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
NIL
raz
clave
hizq her_d
A
C
E F G K L
D H
B I
J
raz
hizq her_d
clave
FI UPV: Curso 2008/2009 Pagina 4.32
EDA-4
5. REPRESENTACI

ON DE

ARBOLES
Con vectores y direccion del padre
1
10
5 6 7 11 12
4 8
2 9 1
10
5 6 7 11 12
4 8
2 9
3 3
1 2 3 4 5 6 7 8 9 10 11 12
3 3 3 1 1 9 4 4 4 10 10 3
El nodo i es la raz del arbol si T[i] = i. Cada nodo apunta a su
padre: T[i] = padre(i).
FI UPV: Curso 2008/2009 Pagina 4.33
EDA-4
5. REPRESENTACI

ON DE

ARBOLES

Arboles binarios: variables dinamicas o vectores


(opcionalmente, puntero al padre)
C
B
D A
G
E
F
2
3
4
....
8
9
10
....
12
13
14
16
17
....
15 F
E
15
3
17
A
D
C
G
2 B
NIL
12
NIL
raz 8
NIL NIL
NIL
NIL NIL
NIL
clave
hder hizq
C
B
D A E
F
G
hizq hder
clave
raz
FI UPV: Curso 2008/2009 Pagina 4.34
EDA-4
5. REPRESENTACI

ON DE

ARBOLES

Arboles binarios (casi-completos): vector


raiz: T[1]
padre[i]=[i/2]
hizquierdo[i]=2i
hderecho[i]=2i+1
A
B C
G
K H I J L
F E D
1
5
8 9 10 11 12
6 7
3 2
4
1 2 3 4 5 6 7 8 9 10 11 12
A I D H J E F G K L
13 14 ...
C B
hizquierdo
talla=12 raz
padre
hderecho
FI UPV: Curso 2008/2009 Pagina 4.35
EDA-4
6. RECORRIDOS DE

ARBOLES BINARIOS
A veces puede interesar un recorrido sistematico y eciente de todos los nodos del arbol.
A
B C
D
E
F
G
H I
J
Recorrido en preorden: A B D E H J I C F G
Recorrido en inorden: D B H J E I A F G C
Recorrido en postorden: D J H I E B G F C A
Recorrido en niveles: A B C D E F H I G J
Coste de todos los algoritmos (n), siendo n el n umero de nodos del arbol despues de la
llamada inicial, la funcion se llama recursivamente exactamente 2 veces para cada nodo del
arbol: una vez para su hijo izquierdo y otra para su hijo derecho.
FI UPV: Curso 2008/2009 Pagina 4.36
EDA-4
6. Recorridos de arboles binarios: PREORDEN
La clave de la raz se imprime antes de los valores de sus subarboles
A
B C
D E
F
G H I
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 Pagina 4.37
EDA-4
6. Recorridos de arboles binarios: INORDEN
La clave de la raz se imprime entre los valores de su subarbol izquierdo y derecho
A
B C
D E
F
G H I
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 Pagina 4.38
EDA-4
6. Recorridos de arboles binarios: POSTORDEN
La clave de la raz se imprime despues de los valores de sus subarboles
A
B C
D E
F
G H I
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 Pagina 4.39
EDA-4
6. Recorridos de arboles binarios: NIVELES
En lugar de una pila (recursion) se utiliza una cola.
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 Pagina 4.40
EDA-4
Ejemplo arboles binarios: arbol de expresiones
Utilizacion de la estructura AB para representar expresiones aritmeticas con operadores
binarios.
raz: operador principal
nodos internos: operadores de subexpresiones
hojas: operandos
(niveles: precedencia relativa de evaluacion)
x
+ -
e
a b
d c /
Recorrido en preorden: + / a b c d e
notacion preja o polaca
Recorrido en inorden: (((a/b) + c) (de))
notacion inja
Recorrido en postorden: a b / c + d e
notacion postja o polaca inversa
FI UPV: Curso 2008/2009 Pagina 4.41
EDA-4
7. RECORRIDOS DE GRAFOS
Metodo para recorrer de forma sistematica y eciente un grafo.
Recorrido en profundidad: generalizacion del recorrido en preorden de
un arbol
Recorrido en amplitud: generalizacion del recorrido en niveles de un
arbol
En todos los algoritmos de recorrido de grafos supondremos que el grafo
esta implementado con listas de adyacencia.
FI UPV: Curso 2008/2009 Pagina 4.42
EDA-4
Recorrido en profundidad de un grafo
Dado un grafo G = (V, A) y un vertice v V , la estrategia de recorrido
en profundidad (Depth-First Search (DFS)), explora sistematicamente
las aristas de G de manera que primero se visitan los vertices adyacentes
a los visitados mas recientemente. De esta forma, se va profundizando
en el grafo; es decir, alejandose progresivamente de v.
Este proceso continua hasta que todos los vertices alcanzables desde el
vertice de la llamada original han sido descubiertos.
Esta estrategia admite una implementacion simple de forma recursiva y
proporciona:
Ordenamientos de los vertices.
Clasicacion de las aristas.
Algunas aplicaciones:
Calcular un posible orden topologico y comprobar si el grafo es acclico.
Encontrar las componentes fuertemente conexas de un grafo.
FI UPV: Curso 2008/2009 Pagina 4.43
EDA-4
Recorrido en profundidad de un grafo
El algoritmo DFS asocia los siguientes datos a cada vertice v del grafo:
d[v] instante en que el vertice v es descubierto
f[v] instante en que naliza la exploracion del vertice v
pr[v] el vertice predecesor de v en el arbol generado (arbol de
exploracion primero en profundidad, es un subgrafo del grafo original).
El color asociado al vertice, que puede ser de 3 tipos:
WHITE cuando nunca ha sido explorado,
GRAY mientras esta siendo explorado,
BLACK cuando ya ha sido explorado.
Al principio todos los vertices se ponen de color WHITE. Se utiliza un
atributo time como contador para marcar los instantes.
FI UPV: Curso 2008/2009 Pagina 4.44
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 Pagina 4.45
EDA-4
Recorrido en profundidad de un grafo: Ejemplo
Grafo:
8 vertices
aristas:
0 1
0 2
0 3
0 4
1 4
2 3
3 1
3 4
5 6
6 7
5 7
7 5
FI UPV: Curso 2008/2009 Pagina 4.46
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 Pagina 4.47
EDA-4
Recorrido en profundidad de un grafo: Ejemplo
v d[v] f[v] pr[v]
0 1 10 -1
1 5 6 3
2 8 9 0
3 4 7 0
4 2 3 0
5 11 16 -1
6 14 15 5
7 12 13 5
FI UPV: Curso 2008/2009 Pagina 4.48
EDA-4
Recorrido en profundidad de un grafo
Clasicacion de las aristas. Una arista (u, v) es de tipo:
TREE o del arbol: si el vertice v ha sido descubierto a traves de
dicha arista. Estas aristas denen el bosque del recorrido primero en
profundidad, formado por uno o mas arboles.
BACK o hacia atras: si v es un antecesor de u en el arbol del recorrido
primero en profundidad.
FORWARD o hacia adelante: si v es un descendiente de u en el arbol
del recorrido primero en profundidad.
CROSS o de cruce: ning un vertice es antecesor del otro.
El recorrido DFS puede ser utilizado para clasicar las aristas a medida
que las va procesando. Cuando desde un vertice u se considera la arista
(u, v), se puede observar el color del vertice destino v:
WHITE indica que es una arista del arbol o TREE.
GRAY indica que es una arista hacia atras o BACK.
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 Pagina 4.49
EDA-4
Recorrido en profundidad de un grafo
Relacion de tipo parentesis: en la b usqueda primero en profundidad,
dados dos vertices del grafo u y v, se cumple exactamente una de estas
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 arbol DFS ni v descendiente
de u.
el intervalo [d[u], f[u]] esta contenido enteramente dentro del inter-
valor [d[v], f[v]] y u es descendiente de v en el arbol DFS.
el intervalo [d[v], f[v]] esta contenido enteramente dentro del intervalor
[d[u], f[u]] y v es descendiente de u en el arbol DFS.
La relacion de estos intervalos tambien sirve para clasicar las aristas,
as la arista (u, v) es:
del arbol si d[u] < d[v] < f[v] < f[u]
hacia atras si d[v] < d[u] < f[u] < f[v]
de cruce si d[v] < f[v] < d[u] < f[u]
FI UPV: Curso 2008/2009 Pagina 4.50
EDA-4
Orden topologico
Un orden topologico de un grafo dirigido acclico G = (V, A) es una
ordenacion de los vertices de forma que si (u, v) A, entonces u aparece
antes que v. (La solucion no es unica.) Ejem.: prerrequisitos de los
estudios.
No es posible la ordenacion topologica cuando existen ciclos!
c
b
e d
a
a b d e c
d a e b c
Orden no unico.
Ordenacion de vertices en eje horizontal con las aristas de izquierda a derecha.
FI UPV: Curso 2008/2009 Pagina 4.51
EDA-4
Orden topologico
Dado un grafo G = (V, A), el DFS puede usarse para determinar si es
acclico y, en ese caso, obtener un orden topologico.
El grafo es acclico si no tiene ninguna arista hacia atras.
El orden en que naliza la exploracion de los vertices (valor guardado
en f[v]) es un orden topologico invertido.
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 Pagina 4.52
EDA-4
Recorrido en profundidad de un grafo: Ejemplo 2
Grafo:
11
0 1
0 2
1 3
2 4
3 2
3 4
3 5
5 7
4 6
4 7
1 8
1 9
8 10
9 10
dfs_visit(0)
(0,2) is a TREE EDGE
dfs_visit(2)
(2,4) is a TREE EDGE
dfs_visit(4)
(4,7) is a TREE EDGE
dfs_visit(7)
(4,6) is a TREE EDGE
dfs_visit(6)
(0,1) is a TREE EDGE
dfs_visit(1)
(1,9) is a TREE EDGE
dfs_visit(9)
(9,10) is a TREE EDGE
dfs_visit(10)
(1,8) is a TREE EDGE
dfs_visit(8)
(8,10) is a FORWARD/CROSS EDGE
(1,3) is a TREE EDGE
dfs_visit(3)
(3,5) is a TREE EDGE
dfs_visit(5)
(5,7) is a FORWARD/CROSS EDGE
(3,4) is a FORWARD/CROSS EDGE
(3,2) is a FORWARD/CROSS EDGE
FI UPV: Curso 2008/2009 Pagina 4.53
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 Pagina 4.54
EDA-4
Otro algoritmo para el orden topologico, sin DFS
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 Pagina 4.55
EDA-4
Recorrido en amplitud de un grafo
Dado un grafo G = (V, A) y un vertice s V , la estrategia de
recorrido en amplitud o en anchura (Breadth-First Search (BFS)),
explora sistematicamente las aristas de G de manera que primero se
visitan los vertices mas cercanos a v.
Algunos algoritmos importantes de grafos tienen una estructura similar
al BFS. Por ejemplo, el algoritmo de Prim para encontrar el arbol de
expansion de mnimo coste, o el algoritmo de Dijkstra para encontrar
los caminos mas cortos desde un vertice dado.
El algoritmo BFS explora todos los vertices a distancia k del vertice
origen s antes de empezar a explorar los vertices a distancia k + 1.
Al igual que DFS, se utiliza un vector de tipo color para marcar los
vertices del grafo como no visitados (WHITE), visitandose (GRAY) o
ya visitados (BLACK).
Tambien se genera un vector de predecesores para obtener un arbol.
FI UPV: Curso 2008/2009 Pagina 4.56
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 Pagina 4.57
EDA-4
Recorrido en amplitud de un grafo: Ejemplo
Grafo:
11
0 1
0 2
1 3
2 4
3 2
3 4
3 5
5 7
4 6
4 7
1 8
1 9
8 10
9 10
FI UPV: Curso 2008/2009 Pagina 4.58
EDA-4
Recorrido en amplitud de un grafo: Ejemplo
Cola: salen< 0 <entran
Cola: salen< 2 1 <entran
Cola: salen< 1 4 <entran
Cola: salen< 4 9 8 3 <entran
Cola: salen< 9 8 3 7 6 <entran
Cola: salen< 8 3 7 6 10 <entran
Cola: salen< 3 7 6 10 <entran
Cola: salen< 7 6 10 5 <entran
Cola: salen< 6 10 5 <entran
Cola: salen< 10 5 <entran
Cola: salen< 5 <entran
v d[v] pr[v]
0 0 -1
1 1 0
2 1 0
3 2 1
4 2 2
5 3 3
6 3 4
7 3 4
8 2 1
9 2 1
10 3 9
FI UPV: Curso 2008/2009 Pagina 4.59

También podría gustarte