Sunteți pe pagina 1din 60

Estructuras de Datos y Algoritmos

Facultad de Inform
atica
Universidad Polit
ecnica de Valencia

Curso 2008/2009
Tema 4:
Grafos y
arboles

FI UPV: Curso 2008/2009

EDA-4

TEMA 4. Grafos y
arboles
Objetivos
Definiciones, representaci
on y recorrido de arboles y grafos.
Contenidos
1
2
3
4
5
6
7
8

Grafos: Definiciones basicas


Representaci
on de grafos

Arboles:
Definiciones basicas

Arboles
binarios
Representaci
on de arboles
Recorridos de arboles binarios
Recorrido de grafos
Orden topol
ogico 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 BASICAS


Grafo dirigido: es un par G = (V, A) donde V es un conjunto finito 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.

FI UPV: Curso 2008/2009

Pagina 4.2

EDA-4

1. GRAFOS: DEFINICIONES BASICAS


Grafo no dirigido: es un par G = (V, A) donde V es un conjunto finito de vertices y
A {{u, v} | u, v V v 6= 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.

1
2

FI UPV: Curso 2008/2009

Pagina 4.3

EDA-4

1. GRAFOS: DEFINICIONES BASICAS


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.

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 BASICAS


Camino desde un vertice u V a un vertice v V : es una secuencia hv0, v1, . . . , vk i de
vertices de G = (V, A) tal que v0 = u, vk = v, (vi, vi+1) A, 0 i < k.
La longitud de un camino hv0, v1, . . . , vk i es el n
umero de aristas que lo forman.
Camino simple: es un camino hv0, v1, . . . , vk i en el que todos sus vertices son distintos,
excepto quizas el primero y el u
ltimo.
Ciclo: es un camino simple hv0, v1, . . . , vk i tal que v0 = vk y el camino contiene al menos
una arista.
Un bucle es un ciclo de longitud 1.

Ejem.: El camino h0, 3, 1, 4i es simple y tiene longitud 3. El camino h0, 1, 4, 3, 1i no es simple.


Ejem.: El camino h1, 4, 3, 1i es un ciclo de longitud 3. El ciclo h5, 5i es un bucle.

Grafo acclico: es un grafo sin ciclos.


FI UPV: Curso 2008/2009

Pagina 4.5

EDA-4

1. GRAFOS: DEFINICIONES BASICAS


Subgrafo: G0 = (V 0, A0) es un subgrafo de G = (V, A) si V 0 V A0 A.
Subgrafo inducido: Dado V 0 V , el subgrafo de G inducido por V 0 es G0 = (V 0, A0)
tal que A0 = {(u, v) A | u, v V 0}.
1

Subgrafo

FI UPV: Curso 2008/2009

Subgrafo inducido por V 0 = {0, 1, 3, 4}

Pagina 4.6

EDA-4

1. GRAFOS: DEFINICIONES BASICAS


V
ertice alcanzable desde un v
ertice 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 relaci
on ser alcanzable.
Un grafo no dirigido es conexo si u, v V , v es alcanzable desde u. Es decir, si tiene
una u
nica componente conexa.
Las componentes fuertemente conexas en un grafo dirigido son las clases de
equivalencia de vertices seg
un la relaci
on ser mutuamente alcanzable.
Un grafo dirigido es fuertemente conexo si u, v V , v es alcanzable desde u.

2
4

FI UPV: Curso 2008/2009

Pagina 4.7

EDA-4

1. GRAFOS: DEFINICIONES BASICAS


Grafo completo: es un grafo G = (V, A) en el que u, v V , u 6= 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).
2
Un grafo se considera denso si |A| |V | .
2
Un grafo se considera disperso si |A| <<< |V | .

FI UPV: Curso 2008/2009

Pagina 4.8

EDA-4

DE GRAFOS: Matriz de adyacencias


2. REPRESENTACION
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
3

4
5

2
3

4
FI UPV: Curso 2008/2009

0
0
0
0
0
0

1
0
0
1
0
0

0
0
0
0
0
0

1
0
0
0
1
0

0
1
1
0
0
0

0
1
0
0
1

1
0
1
1
1

0
1
0
1
0

0
1
1
0
1

1
1
0
1
0

0
0
1
0
0
1

Pagina 4.9

EDA-4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

//
Representacion de Grafos: Matriz de adyacencia
#include <vector>
#include <iostream>
using namespace std;
class grafoDirigidoBitMat {
int numVert;
vector<bool> vec;
int indice(int u, int v) const { return u*numVert+v; }
public:
grafoDirigidoBitMat(int nvert) : numVert(nvert),vec(nvert*nvert) {}
void insertar_arista(int u, int v) { vec[indice(u,v)] = true; }
bool existe_arista(int u, int v) const { return vec[indice(u,v)]; }
void imprime(ostream &s) const;
};
void grafoDirigidoBitMat::imprime(ostream &s) const {
for (int u=0; u < numVert; ++u) {
for (int v=0; v < numVert; ++v)
s << ((vec[indice(u,v)]) ? 1 : 0) << ;
s << endl;
}
}

FI UPV: Curso 2008/2009

Pagina 4.10

EDA-4
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

ostream& operator << (ostream& s, const grafoDirigidoBitMat &grafo) {


grafo.imprime(s); return s;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
cerr << "Uso: " << argv[0] << " maxNodos\n"; exit(0);
}
int numVert = atoi(argv[1]);
grafoDirigidoBitMat gdmat(numVert);
int u,v;
while (cin >> u >> v) { // lectura de aristas
if (0<=u && u<numVert && 0<=v && v<numVert)
gdmat.insertar_arista(u, v);
}
// volcamos la matriz por salida estandar
cout << "\nMatriz de adyacencia\n" << gdmat << endl;
return 0;
}

FI UPV: Curso 2008/2009

Pagina 4.11

EDA-4

DE GRAFOS: Listas de adyacencia


2. REPRESENTACION
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
3

4
5

2
3

4
FI UPV: Curso 2008/2009

1
4
4
1
3
5

1
0
3
4
3

NIL

NIL

NIL

NIL
NIL
NIL

4
4
1
2
0

NIL

NIL

NIL

1
1

NIL
NIL

Pagina 4.12

EDA-4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

//
Representacion de Grafos: Listas de adyacencia
#include <iostream>
using namespace std;
class grafoListaAd {
struct arista {
int vertice_destino;
arista *sig;
arista (int v, arista *s) { vertice_destino=v; sig=s; }
};
int numVert;
arista **vec;
public:
grafoListaAd(int numVert);
bool existe_arista(int u, int v) const;
void insertar_arista(int u, int v, bool nueva=false);
void imprime(ostream &s) const;
};
grafoListaAd::grafoListaAd(int numVert) {
this->numVert = numVert;
vec = new arista*[numVert];
for (int i=0; i < numVert; i++) vec[i] = 0;
}

FI UPV: Curso 2008/2009

Pagina 4.13

EDA-4
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

bool grafoListaAd::existe_arista(int u, int v) const {


for (const arista *r = vec[u]; r != 0; r = r->sig)
if (r->vertice_destino == v) return true;
return false;
}
void grafoListaAd::insertar_arista(int u, int v, bool nueva) {
if (nueva || !existe_arista(u,v))
vec[u] = new arista(v,vec[u]);
}
void grafoListaAd::imprime(ostream &s) const {
for (int i=0; i < numVert; i++) {
s << i << ":";
for (const arista *r = vec[i]; r != 0; r = r->sig) {
if (r != vec[i]) s << ",";
s << r->vertice_destino;
}
s << endl;
}
}
ostream& operator << (ostream& s, grafoListaAd &grafo) {
grafo.imprime(s); return s;
}

FI UPV: Curso 2008/2009

Pagina 4.14

EDA-4
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

int main(int argc, char *argv[]) {


if (argc != 2) {
cerr << "Uso: " << argv[0] << " maxNodos\n"; exit(0);
}
int numVert = atoi(argv[1]);
grafoListaAd list_ad(numVert);
int u,v;
while (cin >> u >> v) { // lectura de aristas
if (0 <= u && u < numVert && 0 <= v && v < numVert)
list_ad.insertar_arista(u, v);
}
// volcado por salida estandar
cout << "\nListas de adyacencia\n" << list_ad << endl;
return 0;
}

FI UPV: Curso 2008/2009

Pagina 4.15

EDA-4

Resumen: Representaci
on de grafos

Matriz de adyacencia
Listas de adyacencia

Espacio
(|V |2)
(|V | + |A|)

Matriz de adyacencia
Listas de adyacencia

Construcci
on del grafo
(|V |2)
(|V | + |A|)

Matriz de adyacencia
Listas de adyacencia
Listas de incidencia

Recorrido sucesores
(|V |)
(grado salida(u))
(|V | + |A|)

FI UPV: Curso 2008/2009

(u, v) A
(1)
(grado salida(u))
Recorrido predecesores
(|V |)
(|V | + |A|)
(grado entrada(u))

Pagina 4.16

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
olo si (v, u) A. Escribe dos
algoritmos que permitan construir el grafo traspuesto Gt 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 modificar el propio grafo:
1
2
3
4
5
6
7
8

void grafoDirigidoBitMat::trasponer () { // in place


for (int u=0; u < vertices; ++u)
for (int v=0; v < u; ++v) {
bool aux
= vec[indice(u,v)];
vec[indice(u,v)] = vec[indice(v,u)];
vec[indice(v,u)] = aux;
}
}

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
2
3
4
5
6
7
8
9
10

grafoListaAd* grafoListaAd::trasponer() const { // devuelve OTRO grafo


grafoListaAd* resul = new grafoListaAd(numVert);
for (int u=0; u < numVert; ++u)
for (const arista *r = vector[u]; r != 0; r = r->sig) {
int v = r->vertice_destino;
// le decimos true para no subir el coste innecesariamente:
resul->insertar_arista(v,u,true);
}
return resul;
}

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 define como


G2 = (V, A0) tal que (u, w) A0 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 G2 a partir de G, suponiendo que este u
ltimo esta representado como una matriz de
adyacencia y como lista de adyacencia.
Calcula el coste temporal de los algoritmos resultantes, justificandolo adecuadamente.

FI UPV: Curso 2008/2009

Pagina 4.20

EDA-4

Ejercicio: Cuadrado de un grafo


Soluci
on con matriz de adyacencia:
1
2
3
4
5
6
7
8
9
10
11
12

grafoDirigidoBitMat* grafoDirigidoBitMat::cuadrado() const {


// devuelve otro grafo
grafoDirigidoBitMat *resul = new grafoDirigidoBitMat(numVert);
for (int u=0; u<numVert; ++u)
for (int v=0; v<numVert; ++v) {
bool camino=false;
for (int w=0; w<numVert && !camino; ++w)
camino = camino || (vec[indice(u,w)] && vec[indice(w,v)]);
resul->vec[indice(u,v)] = camino;
}
return resul;
}

Coste:

FI UPV: Curso 2008/2009

P|V | P|V | P|V |


u=1

v=1

w=1 1

O(|V |3)

Pagina 4.21

EDA-4

Ejercicio: Cuadrado de un grafo


Soluci
on con listas de adyacencia:
1
2
3
4
5
6
7
8

grafoListaAd *grafoListaAd::cuadrado() const {


grafoListaAd *resul = new grafoListaAd(vertices);
for (int u=0; u<vertices; ++u)
for (const arista* r=vec[u]; r!=0; r=r->sig)
for (const arista* s=vec[r->vertice_destino]; s!=0; s=s->sig)
resul->insertar_arista(u, s->vertice_destino);
return resul;
}

FI UPV: Curso 2008/2009

Pagina 4.22

EDA-4

3. ARBOLES:
DEFINICIONES BASICAS
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 0, A0) tal que V 0 = V y A0 A.

Grafo

FI UPV: Curso 2008/2009

Bosque

Arbol

Pagina 4.23

EDA-4

3. ARBOLES:
DEFINICIONES BASICAS
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 u
nico 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 BASICAS

Arbol
enraizado
Un arbol enraizado es un arbol libre con un vertice (o nodo) distinguido denominado raz.
raz

10

8
6

12
5

4
11

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 u
ltimo 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 u
nico 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 BASICAS

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
altura=4 8
6
9

FI UPV: Curso 2008/2009

10
12

profundidad 0
4
11

profundidad 1
2 profundidad 2
profundidad 3
profundidad 4

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
profundidad 0

7
profundidad 1

1
6

altura=3
profundidad 2
profundidad 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
profundidad

num. nodos

1=2_0

2=2_1

4=2_2

8=2_3

h=3

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 = 2i.
Ph1 i
h
0
1
h1
hojas: 2
y nodos internos: 2 + 2 + + 2
= i=0 2 = 2h 1
Ph
nodos total: n = i=0 2i = 2h+1 1
. . . y la altura
n = 2h+1 1
FI UPV: Curso 2008/2009

h = blog2 nc
Pagina 4.28

EDA-4

Propiedades de los
arboles binarios

El maximo n
umero de nodos de profundidad i es 2i.
El maximo n
umero de nodos en un arbol binario de altura h es
2h+1 1. El maximo n
umero de nodos internos es 2h 1. El maximo
n
umero de hojas es 2h.
La altura mnima de un arbol binario con n nodos es blog2 nc.
Para cualquier arbol binario no vaco, si n0 es el n
umero de hojas y
n2 es el n
umero de nodos de grado 2, entonces n0 = n2 + 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

DE ARBOLES

5. REPRESENTACION

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 direcci
on 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

DE ARBOLES

5. REPRESENTACION
Listas (ordenadas) de hijos
raz

10 NIL
11

12 NIL

1
2

1
2

3
4

9
8

10

FI UPV: Curso 2008/2009

11

NIL

NIL

NIL

NIL

12

NIL

NIL

NIL

10

11

NIL

12

NIL

NIL

Pagina 4.31

EDA-4

DE ARBOLES

5. REPRESENTACION
Hijo m
as a la izquierda-Hermano derecha: variables din
amicas o vectores
clave
hizq
her_d
2
3

raz

3 C 10
17 D 9
8 A NIL

raz

....
8 NIL

9 NIL

NIL

10

H
13 I

NIL

12 NIL

NIL

13

G
14 J
NIL K
NIL F
NIL L
NIL E

NIL

14

15

16
17

FI UPV: Curso 2008/2009

....

B 2

....

16
12
7
15

D
E

H
G

J
K

clave
hizq her_d

Pagina 4.32

EDA-4

DE ARBOLES

5. REPRESENTACION
Con vectores y direcci
on del padre

3
2

1
4

9
8

10
11

12

9
8

10

11

12

10

11

10 10

12

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

DE ARBOLES

5. REPRESENTACION

Arboles
binarios: variables din
amicas o vectores
(opcionalmente, puntero al padre)
clave
hizq
hder
2
3

raz

15 A NIL
NIL D NIL
8 C 12

raz

....
8

3 B 2

10

....

12

17 G

NIL

NIL

NIL

13

14

15 NIL

16
17 NIL

F
FI UPV: Curso 2008/2009

....

clave
hizq
hder

Pagina 4.34

EDA-4

DE ARBOLES

5. REPRESENTACION

Arboles
binarios (casi-completos): vector
1
raiz: T[1]
padre[i]=[i/2]
hizquierdo[i]=2i
hderecho[i]=2i+1

2
4
8

B
5

D
9

10

E
11

C
7

12

10

11

12

padre
raz
FI UPV: Curso 2008/2009

13

14

...

hizquierdo
hderecho

talla=12
Pagina 4.35

EDA-4

6. RECORRIDOS DE ARBOLES
BINARIOS
A veces puede interesar un recorrido sistematico y eficiente de todos los nodos del arbol.
A
B

Recorrido en preorden:

ABDEHJICFG

Recorrido en inorden:

DBHJEIAFGC

Recorrido en postorden:

DJHIEBGFCA

Recorrido en niveles:

ABCDEFHIGJ

Coste de todos los algoritmos (n), siendo n el n


umero de nodos del arbol despues de la
llamada inicial, la funci
on 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

9
10
11
12
13

void nodo_abb::preorden() {
cout << valor << endl;
if (h_izq != 0) h_izq->preorden();
if (h_der != 0) h_der->preorden();
}

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

14
15
16
17
18

void nodo_abb::inorden() {
if (h_izq != 0) h_izq->inorden();
cout << valor << endl;
if (h_der != 0) h_der->inorden();
}

FI UPV: Curso 2008/2009

Pagina 4.38

EDA-4

6. Recorridos de
arboles binarios: POSTORDEN
La clave de la raz se imprime despu
es de los valores de sus subarboles
A
B

19
20
21
22
23

void nodo_abb::postorden() {
if (h_izq != 0) h_izq->postorden();
if (h_der != 0) h_der->postorden();
cout << valor << endl;
}

FI UPV: Curso 2008/2009

Pagina 4.39

EDA-4

6. Recorridos de
arboles binarios: NIVELES
En lugar de una pila (recursi
on) se utiliza una cola.
24
25
26
27
28
29
30
31
32
33
34
35
36

void abb::por_niveles() {
cola *c = new cola(); // una cola de nodo_abb*
nodo_abb *n;
c->insertar(raiz);
while (c->extraer(n)) {
if (n != 0) { // se puede poner if (n) {
cout << n->valor << endl;
c->insertar(n->h_izq);
c->insertar(n->h_der);
}
}
delete c;
}

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 evaluaci
on)
x
+
/
a

Recorrido en preorden: + / a b c d e
notaci
on prefija o polaca
Recorrido en inorden: (((a/b) + c) (d e))
notaci
on infija
Recorrido en postorden: a b / c + d e
notaci
on postfija o polaca inversa

FI UPV: Curso 2008/2009

Pagina 4.41

EDA-4

7. RECORRIDOS DE GRAFOS

Metodo para recorrer de forma sistematica y eficiente un grafo.


Recorrido en profundidad: generalizaci
on del recorrido en preorden de
un arbol
Recorrido en amplitud: generalizaci
on 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 implementaci
on simple de forma recursiva y
proporciona:
Ordenamientos de los vertices.
Clasificaci
on de las aristas.
Algunas aplicaciones:
Calcular un posible orden topol
ogico 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:
instante en que el vertice v es descubierto
f[v] instante en que finaliza la exploraci
on del vertice v
pr[v] el v
ertice predecesor de v en el arbol generado (arbol de
exploraci
on 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.
d[v]

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

void grafo::dfs_visit(int u) {// algoritmo recursivo del DFS


color[u] = GRAY;
d[u] = ++time;
for (arista *r = vec[u]; r != 0; r = r->sig) {
int v = r->vertice_destino;
if (color[v] == WHITE) { pr[v] = u;
dfs_visit(v); }
}
color[u] = BLACK;
f[u] = ++time;
}
void grafo::dfs() {
for (int u=0; u < numVert; ++u) { color[u] = WHITE;
pr[u] = -1;
}
time = 0;
for (int u=0; u < numVert; ++u)
if (color[u] == WHITE) dfs_visit(u);
}

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
0
1
2
3
4
5
6
7

FI UPV: Curso 2008/2009

d[v]
1
5
8
4
2
11
14
12

f[v]
10
6
9
7
3
16
15
13

pr[v]
-1
3
0
0
0
-1
5
5

Pagina 4.48

EDA-4

Recorrido en profundidad de un grafo


Clasificaci
on 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 definen 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 clasificar 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


Relaci
on 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 intervalor [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 relaci
on de estos intervalos tambien sirve para clasificar 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 topol
ogico
Un orden topol
ogico de un grafo dirigido acclico G = (V, A) es una
ordenaci
on de los vertices de forma que si (u, v) A, entonces u aparece
antes que v. (La soluci
on no es u
nica.) Ejem.: prerrequisitos de los
estudios.
No es posible la ordenaci
on topol
ogica cuando existen ciclos!
a

c
d

Orden no u
nico.
Ordenaci
on de vertices en eje horizontal con las aristas de izquierda a derecha.

FI UPV: Curso 2008/2009

Pagina 4.51

EDA-4

Orden topol
ogico
Dado un grafo G = (V, A), el DFS puede usarse para determinar si es
acclico y, en ese caso, obtener un orden topol
ogico.
El grafo es acclico si no tiene ninguna arista hacia atras.
El orden en que finaliza la exploraci
on de los vertices (valor guardado
en f [v]) es un orden topol
ogico invertido.
1
2
3
4
5
6
7
8
9
10
11
12
13

void grafo::dfs_visit(int u) {
color[u] = GRAY;
d[u] = ++time;
for (arista *r = vec[u]; r != 0; r = r->sig) {
int v = r->vertice_destino;
if (color[v] == WHITE) { pr[v] = u;
dfs_visit(v);
} else if (color[v] == GRAY) es_aciclico = false;
} // es_aciclico esta a true antes de empezar DFS
color[u] = BLACK;
f[u] = time;
topologic_sort.push_front(u); // insertar al ppio
}

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

FI UPV: Curso 2008/2009

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

Pagina 4.53

EDA-4

Recorrido en profundidad de un grafo: Ejemplo 2

v
0
1
2
3
4
5
6
7
8
9
10

d[v]
1
10
2
17
3
18
6
4
15
11
12

f[v]
22
21
9
20
8
19
7
5
16
14
13

pr[v]
-1
0
0
1
2
3
4
4
1
1
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 topol


ogico, sin DFS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

void grafo::orden_topologico_sin_dfs() { // test aciclicidad


int u,v; arista *r;
for (v=0; v < numVert; ++v) grado_entrada[v] = 0;
for (v=0; v < numVert; ++v)
for (r = vec[v]; r != 0; r = r->sig)
grado_entrada[r->vertice_destino]++;
col->vaciar();
for (v=0; v < numVert; v++)
if (grado_entrada[v] == 0) col->insertar(v);
for (n = 0; col->extraer(u); n++) {
topologic_sort.push_back(u); // insertar al final
for (arista *r = vec[u]; r != 0; r = r->sig) {
grado_entrada[r->vertice_destino]--;
if (grado_entrada[r->vertice_destino] == 0)
col->insertar(r->vertice_destino);
}
}
es_aciclico = (n == numVert);
}

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
expansi
on 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

void grafo::bfs(int vertice) {


cola.clear();
for (int u=0; u < numVert; ++u) {
color[u]=WHITE;
pr[u]=-1; d[u]=numVert+1;
// numVert+1> cualquier distancia en el grafo
}
cola.push_back(vertice);
d[vertice] = 0;
while (!cola.empty()) {
int u = cola.front(); cola.pop_front(); // extraer
for (arista *r = vec[u]; r != 0; r = r->sig) {
int v = r->vertice_destino;
if (color[v] == WHITE) {
color[v]=GRAY; d[v]=d[u]+1; pr[v]=u;
cola.push_back(v);
}
}
color[u] = BLACK;
}
}

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:
Cola:
Cola:
Cola:
Cola:
Cola:
Cola:
Cola:
Cola:
Cola:
Cola:

FI UPV: Curso 2008/2009

salen<
salen<
salen<
salen<
salen<
salen<
salen<
salen<
salen<
salen<
salen<

0 <entran
2 1 <entran
1 4 <entran
4 9 8 3 <entran
9 8 3 7 6 <entran
8 3 7 6 10 <entran
3 7 6 10 <entran
7 6 10 5 <entran
6 10 5 <entran
10 5 <entran
5 <entran

v
0
1
2
3
4
5
6
7
8
9
10

d[v]
0
1
1
2
2
3
3
3
2
2
3

pr[v]
-1
0
0
1
2
3
4
4
1
1
9

Pagina 4.59

S-ar putea să vă placă și