estructura de datos 2

60
Capítulo 6 Relaciones binarias y grafos En este capítulo nos centraremos en el modelo de las relaciones binarias 1 entre elementos de dos dominios A y B, donde un elemento de A está relacionado con un elemento de B si se cumple el enunciado de la relación. Generalmente, un elemento de A estará relacionado con varios de B y viceversa; por ello, en algunos textos informáticos las relaciones binarias se denominan relaciones m:n como abreviatura de: m elementos de A se relacionan con n de B y viceversa. Un ejemplo de aplicación de las relaciones binarias podría ser la gestión de la matriculación de alumnos en una universidad. La estructura necesaria se puede considerar como una relación entre dos conjuntos de elementos: los alumnos y las asignaturas, por la que cada alumno está relacionado con todas las asignaturas que cursa y cada asignatura con todos los alumnos que se han matriculado de la misma. IP IC Alg Fis PM ILo EDA Abad x x x x Abadía x x x x Aguilar x x x ... Fig. 6.1: representación de la relación alumnos-asignaturas (la cruz significa que el alumno cursa la asignatura). Dado el contexto de uso esperado, las operaciones sobre el tipo que parecen adecuadas son: matricular un alumno de una asignatura, desmatricularlo (cuando la ha aprobado), averiguar si un alumno cursa una asignatura concreta, y listar las asignaturas que cursa un alumno y los alumnos que cursan una asignatura. Extrapolando estas operaciones a un marco general, podemos formular una especificación para las relaciones y deducir implementaciones eficientes. Concretamente, en la primera sección estudiaremos la Relaciones binarias y grafos 305 __________________________________________________________________________________ 1 Si bien nos podríamos plantear el estudio de relaciones sobre un número arbitrario de dominios, el caso habitual es el binario y por eso nos limitamos a éste.

description

ayuda a la materia universitaria del mismo nombre

Transcript of estructura de datos 2

  • Captulo 6 Relaciones binarias y grafos

    En este captulo nos centraremos en el modelo de las relaciones binarias1 entre elementosde dos dominios A y B, donde un elemento de A est relacionado con un elemento de B sise cumple el enunciado de la relacin. Generalmente, un elemento de A estar relacionadocon varios de B y viceversa; por ello, en algunos textos informticos las relaciones binarias sedenominan relaciones m:n como abreviatura de: m elementos de A se relacionan con n deB y viceversa.

    Un ejemplo de aplicacin de las relaciones binarias podra ser la gestin de la matriculacinde alumnos en una universidad. La estructura necesaria se puede considerar como unarelacin entre dos conjuntos de elementos: los alumnos y las asignaturas, por la que cadaalumno est relacionado con todas las asignaturas que cursa y cada asignatura con todos losalumnos que se han matriculado de la misma.

    IP IC Alg Fis PM ILo EDAAbad x x x xAbada x x x xAguilar x x x...

    Fig. 6.1: representacin de la relacin alumnos-asignaturas(la cruz significa que el alumno cursa la asignatura).

    Dado el contexto de uso esperado, las operaciones sobre el tipo que parecen adecuadasson: matricular un alumno de una asignatura, desmatricularlo (cuando la ha aprobado),averiguar si un alumno cursa una asignatura concreta, y listar las asignaturas que cursa unalumno y los alumnos que cursan una asignatura. Extrapolando estas operaciones a unmarco general, podemos formular una especificacin para las relaciones y deducirimplementaciones eficientes. Concretamente, en la primera seccin estudiaremos la

    Relaciones binarias y grafos 3 0 5__________________________________________________________________________________

    1 Si bien nos podramos plantear el estudio de relaciones sobre un nmero arbitrario de dominios, elcaso habitual es el binario y por eso nos limitamos a ste.

  • especificacin y la implementacin de las relaciones binarias en general, mientras que en elresto del captulo nos centraremos en el caso particular de relaciones binarias sobre un nicodominio, denominadas grafos. Sobre los grafos se definen varios algoritmos de gran inters,cuya resolucin ser ampliamente comentada y en cuya implementacin intervendrndiversos TAD ya conocidos, como las colas prioritarias y las relaciones de equivalencia.

    6.1 Relaciones binarias

    Se quiere especificar el TAD de las relaciones binarias R AxB definidas sobre dos dominiosde datos A y B, tal que todo valor R del TAD, R R AxB, es un conjunto de pares ordenados, a A y b B. Dados R R AxB, a A y b B, la signatura del tipo es:

    - Crear la relacin vaca: crea, devuelve .

    - Aadir un par a la relacin: inserta(R, a, b), devuelve R {}.- Borrar un par de la relacin: borra(R, a, b), devuelve R - {}.- Mirar si un par de elementos estn relacionados: existe?(R, a, b), averigua si R.- Dos operaciones para determinar el conjunto recorrible2 de elementos (v. fig. 4.27) que

    estn relacionados con uno dado: fila(R, a) , devuelve el conjunto s P(B), definidocomo b s R, y columna(R, b), que se define simtricamente.

    Alternativamente, se podra considerar la relacin como una funcin de pares de elementosen el lgebra booleana B de valores cierto y falso, f : A x B B, en la que f(a, b) vale cierto sia y b estn relacionados. Este modelo se adoptar en el caso de relaciones binariasvaloradas, que se introduce ms adelante.

    En la figura 6.2 se presenta una especificacin para las relaciones. Notemos que aparecendiferentes parmetros formales. Por un lado, los gneros sobre los cuales se define larelacin as como sus operaciones de igualdad, imprescindibles en la especificacin. Porotro lado, y para establecer un criterio de ordenacin de los elementos al insertarlos en elconjunto recorrible, se requiere que los gneros presenten una operacin de comparacinadicional, tal como establece el universo ELEM_

  • determinar su signatura. Los tipos resultantes son implcitamente exportados y podrn serempleados por los mdulos usuarios de las relaciones para declarar variables o parmetros.

    Por lo que respecta a las ecuaciones, la relaciones establecidas sobre inserta confirman quela relacin representa un conjunto de pares. Notemos tambin que, al borrar, hay que sacartodas las posibles apariciones del par y que si el par no existe la relacin queda igual. Porltimo, cabe destacar que la insercin reiterada de elementos en obtener una fila o columnano afecta el resultado por las ecuaciones propias de los conjuntos recorribles.

    universo RELACIN (A, B son ELEM_

  • El uso de las relaciones exige a veces, no slo relacionar pares de elementos, sino tambinexplicitar un valor que caracteriza este nexo, en cuyo caso diremos que la relacin esvalorada; en el ejemplo de la fig. 6.1, esto sucede si se quiere guardar la nota que un alumnoobtiene de cada asignatura que cursa. El modelo resultante exige algunos cambios en laespecificacin y, posteriormente, en la implementacin. Por lo que respecta al modelo, larelacin se puede considerar como una funcin de dos variables (los dominios de la relacin)sobre el codominio V de los valores, f : A x B V, de manera que f(a, b) represente el valorde la relacin. Supondremos que V presenta un valor especial tal que, si a y b no estnrelacionados, consulta(f, a, b) = y, as, la funcin f siempre es total. De lo contrario, deberaaadirse una operacin definida?: relacin A.elem B.elem bool para ver si un par est enel dominio de la funcin y considerar un error que se consulte el valor de un par indefinido.

    En la figura 6.3 se presenta la signatura del TAD (la especificacin queda como ejercicio parael lector); notemos que el gnero de los valores y el valor se definen en el universoELEM_ESP (v. fig. 4.1). Las operaciones fila y columna no slo devuelven los elementoscon que se relacionan sino tambin el valor, por lo que los conjuntos resultantes son depares de elementos que se forman como instancia del universo genrico PAR, en las que elconcepto de igualdad tan slo tiene en cuenta el componente elemento y no el valor.

    universo RELACIN_VALORADA (A, B son ELEM_

  • En el resto de la seccin estudiaremos la implementacin del TAD de las relaciones binariasno valoradas; la extensin al caso valorado queda como ejercicio para el lector.

    La representacin ms intuitiva del tipo de las relaciones binarias consiste en usar un vectorbidimensional de booleanos, con lo que se registra si el par correspondiente a cada posicinpertenece o no a la relacin. Si hay muchos elementos interrelacionados esta solucinpuede ser satisfactoria, pero no lo ser en el caso general, principalmente por razones deespacio y tambin por la ineficiencia de fila y columna, que quedan de orden linealindependientemente del nmero de elementos que en hay en ellas. Por ejemplo, siconsideramos una universidad que imparta 400 asignaturas con una media de 6 asignaturascursadas por alumno, la matriz de la fig. 6.1 estar ocupada slo en un 1.5% de susposiciones. Estas matrices se denominan matrices dispersas (ing., sparse matrix) y esevidente que su representacin exige buscar una estrategia alternativa.

    Una implementacin ms razonable guarda slo los elementos no nulos de la matriz dispersa;cada elemento formar parte exactamente de dos listas diferentes: la de elementos de su filay la de elementos de su columna. En vez de duplicar los elementos en cada lista, se lesasocian dos campos de encadenamiento y as pueden insertarse en las dos listassimultneamente. Esta estrategia ser especialmente til cuando la relacin sea valorada,porque no har falta duplicar el valor de la relacin en varias listas diferentes. La estructura sedenomina multilista de grado dos ; multilista, porque los elementos forman parte de ms deuna lista, y de grado dos, porque forman parte exactamente de dos listas. Para abreviar, a lasmultilistas de grado dos las llamaremos simplemente multilistas (ing., multilist).

    Dada esta poltica de representacin, las operaciones sobre las relaciones quedan as:

    - Insertar un par: se busca la lista de la fila y la columna del elemento y se encadena lacelda. Las celdas se han de mantener odenadas porque la especificacin estableceque fila y columna deben devolver un conjunto ordenado y as no es necesario unproceso explcito de ordenacin; adems, la obtencin ordenada de los elementospuede ser til en algunos contextos. Notemos que la insercin ordenada no enlenteceen exceso la operacin porque, igualmente, para evitar las repeticiones hay querecorrer una de las listas para ver si el par existe o no.

    - Borrar un par: se busca el par en la fila o la columna involucradas. Para actualizar las listashay que conocer la posicin que ocupan los elementos que lo preceden, lo que exigiruna exploracin adicional en la lista en la que no se haya buscado el par. Esta segundabsqueda puede evitarse encadenando doblemente las listas correspondientes.

    - Comprobar si un par existe: hay que recorrer una de las dos listas a la que pertenecehasta encontrarlo o llegar al final sin xito. En el caso de que la longitud esperada deuno de los dos tipos de listas (de filas o de columnas) sea significativamente menor quela del otro, tal vez resulte mejor buscar en las primeras.

    - Obtener una fila o columna: hay que recorrer la lista y formar el conjunto resultante.

    Relaciones binarias y grafos 3 0 9__________________________________________________________________________________

  • Existen todava un par de detalles por concretar:

    - Todas las celdas de una fila y de una columna estn encadenadas, pero no hay uncamino de acceso a la primera celda. Es necesario, pues, aadir una tabla que asocie acada elemento su lista; si el nmero de filas y columnas es acotado y enumerable, sepuede implementar la tabla con un simple vector de apuntadores a la primera celda decada fila y de cada columna, si no, hay que organizar estos apuntadores en una lista obien utilizar tablas de dispersin o rboles de bsqueda, si se pide un acceso eficiente.

    - Los nodos se almacenan en un nico vector o en memoria dinmica segn se conozcao no el nmero de pares que habr en la relacin.

    - Dentro de las celdas no hay ninguna informacin que indique qu columna o filarepresentan. Hay varias soluciones a este problema:

    Aadir a cada celda los identificadores de la fila y la columna a los que pertenece. Esla solucin ptima en tiempo, a costa de mantener dos campos adicionales.

    Cerrar circularmente las listas, de forma que el ltimo nodo de cada lista "apunte" asu cabecera; entonces la cabecera tendr que identificar la fila o columnacorrespondiente. Hay que resaltar que, en este contexto, la circularidad significaque el ltimo elemento de una lista se encadena a su apuntador de inicio citado enel punto anterior. Esta opcin es ms costosa en tiempo, porque para saber la fila o lacolumna a la que pertenece un elemento hay que recorrer la lista hasta el final. Encuanto al espacio, puede acarrear ms o menos problemas segn el uso devectores o punteros en las diferentes estructuras encadenadas, y dependiendo deque la relacin sea valorada o no, lo que puede permitir aprovechar campos yaexistentes o bien obligar a declarar alguno adicional, posiblemente usando elmecanismo de tuplas variantes, si el lenguaje de programacin lo presenta.

    Se puede optar por una solucin intermedia: un tipo de listas con identificadores yel otro circular. Esta solucin es til cuando la longitud esperada de uno de los dostipos es pequea; as, en el ejemplo de alumnos y asignaturas, como la lista deasignaturas por alumno siempre ser muy corta, se podr implementar circularmente,mientras que para las otras parece mas adecuado el uso de identificadores.

    En la figura 6.4 se muestra una representacin de las multilistas en las que tanto las filascomo las columnas forman listas circulares, usando vectores para acceder al inicio eimplementando con punteros las estructuras lineales necesarias; se supone pues que losgneros A y B son vlidos como ndice de vector lo que se traduce en el uso deELEM_ORDENADO como universo de caracterizacin. Destacamos el uso de tuplasvariantes para la implementacin del tipo de las celdas, y de diversas operaciones privadascuyo comportamiento se especifica convenientemente. Notemos tambin que la ausenciade fantasmas complica algunos algoritmos, pero aun as no se incluyen para ahorrar espacio ala estructura. Por ltimo, destaquemos que el invariante evita que dos listas de filas o doslistas de columnas compartan nodos, porque se violara la condicin de igualdad dada.

    3 1 0 Estructuras de datos. Especificacin, diseo e implementacin __________________________________________________________________________________

  • universo MULTILISTA_TODO_CIRCULAR (A, B son ELEM_ORDENADO)implementa RELACIN (A, B son ELEM_
  • funcin inserta (r es relacin; a es A.elem; b es B.elem) devuelve relacin esvar antf, antc, p son ^nodo; est? es bool fvar

    := busca(r, a, b) si est? entonces {si existe, nada}

    p := obtener_espaciosi p = NULO entonces error {no hay espacio}si no {insercin ordenada en la lista de filas, controlando si la fila est vaca}

    si antf = NULO entonces p^.ult_fil := (r.fil[a] = NULO) si no p^.ult_fil := antf^.ult_fil fsisi p^.ult_fil entonces p^.punt_fil := a si no p^.enc_fil := antf^.enc_fil fsisi antf = NULO entonces r.fil[a] := p si no antf^.ult_fil := falso; antf^.enc_fil := p fsi

    {repeticin del proceso en la lista de columnas}si antc = NULO entonces p^.ult_col := (r.col[b] = NULO) si no p^.ult_col := antc^.ult_col fsisi p^.ult_col entonces p^.punt_col := b si no p^.enc_col := antc^.enc_col fsisi antc = NULO entonces r.col[b] := p si no antc^.ult_col := falso; antc^.enc_col := p fsi

    fsifsi

    devuelve r

    funcin borra (r es relacin; a es A.elem; b es B.elem) devuelve relacin esvar antf, antc, p son ^nodo; est? es bool fvar

    {si existe, se obtienen los apuntadores a la celda y a sus predecesores en las listas} := busca(r, a, b)si est? entonces {si no existe, nada}

    {supresin de la lista de filas, vigilando si es el primero y/o el ltimo}opcin

    caso antf = NULO p^.ult_fil? hacer r.fil[a] := NULOcaso antf = NULO p^.ult_fil? hacer r.fil[a] := p^.enc_filcaso antf NULO p^.ult_fil? hacer antf^.ult_fil? := cierto; antf^.punt_fil := acaso antf NULO p^.ult_fil? hacer antf^.enc_fil := p^.enc_fil

    fopcin{repeticin del proceso en la lista de la columna}

    opcincaso antc = NULO p^.ult_col? hacer r.col[b] := NULOcaso antc = NULO p^.ult_col? hacer r.col[b] := p^.enc_colcaso antc NULO p^.ult_col? hacer antc^.ult_col? := cierto; antc^.punt_col := acaso antc NULO p^.ult_col? hacer antc^.enc_col := p^.enc_col

    fopcinliberar_espacio(p)fsi

    devuelve r

    Fig. 6.4: universo para la implementacin del tipo abstracto de las relaciones (cont.).

    3 1 2 Estructuras de datos. Especificacin, diseo e implementacin __________________________________________________________________________________

  • {Funciones fila y columna: siguen el encadenamiento correspondiente y, para cadacelda, averiguan la columna o la fila siguiendo el otro campo. Esta indagacin se lleva atrmino usando diversas funciones auxiliares}funcin fila (r es relacin; a es A.elem) funcin columna (r es relacin; b es B.elem)

    devuelve cjt_b es devuelve cjt_a esvar s es cjt_b; p es ^nodo fvar var s es cjt_a; p es ^nodo fvar

    s := crea; p := r.fil[a] s :=crea; p := r.col[b]si p NULO entonces si p NULO entonces

    mientras p^.ult_fil? hacer mientras p^.ult_col? hacers := aade(s, qu_col(r, p)) s := aade(s, qu_fil(r, p))p := p^.enc_fil p := p^.enc_col

    fmientras fmientrass := aade(s, qu_col(r, p)) s := aade(s, qu_fil(r, p))

    fsi fsidevuelve s devuelve s

    {Funcin busca_col(r, p) : usada en busca, busca la columna querepresenta p dentro de la relacin r y, adems, devuelve el apuntador al anterior dentrode la lista de la columna (que valdr NULO si el elemento es el primero de la columna);existe una funcin busca_fil, similar pero actuando sobre las listas de filas

    P p NULO (b: bB.elem: pcadena_col(r.col[b]))Q qu_b = cabecera_col(p)

    (antc NULO antc^.enc_col = p) (antc = NULO r.col[qu_b] = p), siendo cadena_col similar a cadena siguiendo el encadenamiento de columna}funcin privada busca_col (r es relacin; p es ^nodo) devuelve esvar antc, p, temp son ^nodo; qu_b es bool fvar

    {primero, se busca la columna}temp := pmientras temp^.ult_col? hacer temp := temp^.enc_col fmientrasqu_b := temp^.punt_col {ya est localizada}

    {a continuacin, se busca el anterior a p en la columna}antc := NULO; temp := r.col[qu_b]mientras temp p hacer antc := temp; temp := temp^.enc_col fmientras

    devuelve

    {Funcin auxiliar qu_col(r, p): busca la columna que representa p dentro de la relacin r ;existe una funcin qu_fil, similar pero actuando sobre las filas.

    P p NULO (b: bB.elem: pcadena_col(r.col[b]))Q qu_col(r, p) = cabecera_col(p) }

    funcin privada qu_col (r es relacin; p es ^nodo) devuelve B.elem esmientras p^.ult_col? hacer p := p^.enc_col fmientras

    devuelve p^.punt_col

    Fig. 6.4: universo para la implementacin del tipo abstracto de las relaciones (cont.).

    Relaciones binarias y grafos 3 1 3__________________________________________________________________________________

  • {Funcin auxiliar busca(r, a, b) : en caso que el par exista, pone encontrado a cierto y devuelve: el apuntador p al elemento que lo representadentro de las listas de filas y de columnas de la relacin r, y tambin los apuntadores antf yantc a sus antecesores en estas listas; en caso que el par sea el primero de alguna listadevuelve NULO en el puntero correspondiente al anterior en esta llista. En caso que el par no exista pone encontrado a falso y antf y antc apuntan a los anteriores (segn elcriterio de ordenacin correspondiente) de b y de a en las listas correspondientes a la filaa y a la columna b; en caso que a o b no tengan menores en la lista correspondiente, elpuntero devuelto vale NULO

    P ciertoQ encontrado q: qcadena_fil(r.fil[a]): cabecera_col(q) = b

    encontrado (cabecera_fil(p) = a) (antf NULO antf^.enc_fil = p) (cabecera_col(p) = b) (antc NUL antc^.enc_col = p)

    encontrado (antf NULO cabecera_col(antf) < b) (antc NULO cabecera_fil(antc) < a) (antf = NULO r.fil[a] NULO) cabecera_col(r.fil[a]) > b (antc = NULO r.col[b] NULO) cabecera_fil(r.col[b]) > a

    siendo cadena_fil similar a cadena siguiendo el encadenamiento de fila}funcin privada busca (r es relacin; a es A.elem; b es B.elem)

    devuelve esvar encontrado, xito es bool; antf, antc, p son ^nodo; qu_b es B.elem fvar

    encontrado := falso; xito := falsosi r.fil[a] = NULO entonces antf := NULOsi no p := r.fil[a]; antf := NULO {se busca por la fila; antf : anterior en la fila}

    mientras p^.ult_fil? xito hacer := busca_col(r, p) {antc : anterior en la columna}si qu_b b entonces xito := cierto; encontrado := (qu_b = b)

    si no antf := p; p := p^.enc_filfsi

    fmientrassi xito entonces { tratamiento de la ltima clave }

    := busca_col(r, p)si qu_b = b entonces encontrado := cierto

    si no si qu_b < b entonces antf := p fsifsi

    fsifsi... repeticin del proceso en la lista de columnas

    devuelve

    funiverso

    Fig. 6.4: universo para la implementacin del tipo abstracto de las relaciones (cont.).

    3 1 4 Estructuras de datos. Especificacin, diseo e implementacin __________________________________________________________________________________

  • 6.2 Grafos

    En la seccin anterior hemos introducido el TAD de las relaciones binarias sobre dosdominios cualesquiera de elementos; si los dos dominios son el mismo, la relacin sedenomina grafo3 (ing., graph). Por ello, se puede considerar un grafo como un conjunto depares ordenados tales que los elementos de cada par cumplen el enunciado de la relacin;los elementos del dominio de la relacin se llaman vrtices o nodos (ing., vertex o node) y elpar que representa dos vrtices relacionados se llama arista o arc (ing., edge o arc).

    Un ejemplo tpico de grafo es la configuracin topolgica de una red metropolitana detransportes, donde los vrtices son las estaciones y las aristas los tramos que las conectan. Amenudo los grafos representan una distribucin geogrfica de elementos dentro delespacio4 (ciudades, componentes dentro de un circuito electrnico, computadorespertenecientes a una red, etc.). La representacin de la red metropolitana en forma de grafopermite formular algunas cuestiones interesantes, como por ejemplo averiguar el camino msrpido para ir de una estacin a otra. El estudio de ste y otros algoritmos configura el ncleocentral del resto del captulo. Hay que destacar, no obstante, que no se introducen algunasversiones especialmente hbiles de estos algoritmos, puesto que su dificultad excede losobjetivos de este libro, sobre todo en lo que se refiere al uso de estructuras de datosavanzadas; el lector que est interesado puede consultar, por ejemplo, [BrB87] para unavisin general y [CLR90] para un estudio en profundidad.

    Del mismo modo que hay varios tipos de listas o de rboles, se dispone de diferentesmodelos de grafos. Concretamente, definimos cuatro TAD que surgen a partir de las cuatrocombinaciones posibles segn los dos criterios siguientes:

    - Un grafo es dirigido (ing., directed; tambin se abrevia por digrafo) si la relacin no essimtrica; si lo es, se denomina no dirigido.

    - Un grafo es etiquetado (ing., labelled o weighted) si la relacin es valorada; si no lo es,se denomina no etiquetado. Los valores de la relacin son sus etiquetas (ing., label).

    En la fig. 6.5 se presenta un ejemplo de cada tipo. Para mostrar los grafos grficamente, seencierran en un crculo los identificadores de los vrtices y las aristas se representanmediante lneas que unen estos crculos; las lneas llevan una flecha si el grafo es dirigido y,si es etiquetado, el valor de la etiqueta aparece a su lado. En cada caso se dice cul es elconjunto V de vrtices y el enunciado R de la relacin. En el resto de la seccinestudiaremos detalladamente la especificacin y la implementacin de los grafos dirigidos yetiquetados, y comentaremos brevemente los otros modelos.

    Relaciones binarias y grafos 3 1 5__________________________________________________________________________________

    3 Hay una clase particular de grafos, llamados grafos bipartitos (ing., bipartite graph ), que puedendefinirse sobre dos dominios distintos, que no se estudian aqu; v., por ejemplo, [AHU83, pp.245-249].4 De hecho, los grafos fueron definidos en el siglo XVIII por el matemtico L. Euler para decidir si eraposible atravesar todos los puentes de la ciudad de Knigsberg, Prusia (actualmente Kaliningrado,Rusia, ciudad baada por un ro que rodea una isla) sin pasar ms de una vez por ninguno de ellos.

  • Barcelona

    Madrid

    Crdoba621

    908

    400

    Ejemplo 4. Tiempo de viaje.V = {Barcelona, Madrid, Las Palmas}R = "horas transcurridas"

    Ejemplo 1: Transportes Metropolitanosde Barcelona

    V = {Horta, Sants, Espanya, Clot, Montbau}R = "estn en la misma linea"

    Horta Sants

    Espanya Montbau

    Clot

    Ejemplo 2. Conjunto de frmulas.V = {A1, B5, D9, E3, H12}R = "usa en su definicin"

    Ejemplo 3. Distancia entre ciudades.V = {Barcelona, Madrid, Crdoba}R = "distancia"

    A1

    E3 B5

    D9A1 = B5+D9*H12H12 = B5-E3B5 = D9+1

    H12

    Madrid

    1 1

    24

    31

    Las Palmas

    Barcelona

    Fig. 6.5: diversos ejemplos de grafos.

    3 1 6 Estructuras de datos. Especificacin, diseo e implementacin __________________________________________________________________________________

  • 6.2.1 Modelo y especificacin

    Dado un dominio V de vrtices y un dominio E de etiquetas, definimos un grafo dirigido yetiquetado, g, como una funcin que asocia etiquetas a pares de vrtices, g {f : V x V E }(igual que las relaciones binarias valoradas, de las cuales son un caso particular). A partir deahora, denotaremos por n el nmero de vrtices del grafo g {f : V x V E }, n = ||V ||, y por ael nmero de aristas, a = ||dom(g)||. Por lo que respecta al resto de modelos, en los grafos nodirigidos tenemos que, dados dos vrtices cualesquiera u y v, se satisface la condicindom(g) dom(g) g(u, v) = g(v, u), mientras que en el caso de grafos g noetiquetados, el codominio de la funcin es el lgebra B de valores cierto y falso,g {f : V x V B}, donde g(u, v) vale cierto si u y v cumplen el enunciado de la relacin5.

    Cabe destacar que la mayora de textos del mbito de las estructuras de datos definen ungrafo como un par ordenado de dos conjuntos, el conjunto de vrtices y el conjunto dearistas. La especificacin, la implementacin y los diversos algoritmos sobre grafos que sepresentan en este libro pueden adaptarse sin problemas a este modelo.

    De ahora en adelante supondremos que V es finito (y, por consiguiente, dom(g) tambin); sino, la mayora de los algoritmos y las implementaciones que estudiaremos en las prximassecciones no funcionarn. Supondremos tambin que no hay aristas de un vrtice a smismo (es decir, que la relacin es antirreflexiva), ni ms de una arista entre el mismo par devrtices si el grafo es no dirigido, ni ms de una arista en el mismo sentido entre el mismo parde vrtices si el grafo es dirigido; estas propiedades sern garantizadas por la especificacinalgebraica del tipo. En estas condiciones, el nmero mximo de aristas6 de un grafo dirigidode n nodos es n 2-n, si de cada nodo sale una arista al resto (en los grafos no dirigidos, hayque dividir esta magnitud por dos); este grafo se denomina completo (ang., complete o full).Si el grafo no es completo, pero el nmero de aristas se acerca al mximo, diremos que esdenso ; por el contrario, si el grafo tiene del orden de n aristas o menos, diremos que esdisperso. Supondremos, por ltimo, que E presenta un valor especial , que denota lainexistencia de arista; si el valor no puede identificarse en E, se pueden hacer las mismasconsideraciones que en el TAD de las relaciones valoradas.

    Dado g un grafo dirigido y etiquetado, g {f : V x V E }, dados u,vV dos vrtices y e Euna etiqueta, e , definimos las siguientes operaciones sobre el tipo:

    - Crear el grafo vaco: crea, devuelve la funcin tal que dom() = . Es decir, representa el grafo con todos los vrtices, pero sin ninguna arista.

    - Aadir una nueva arista al grafo: aade(g, u, v, e) devuelve el grafo g' definido como: dom(g') = dom(g) {} g'(u, v) = e u',v': dom(g') - {}: g'(u', v') = g(u', v').

    Relaciones binarias y grafos 3 1 7__________________________________________________________________________________

    5 En este tipo de grafo se puede adoptar tambin el modelo R VxV de las relaciones no valoradas.6 El nmero mximo de aristas interviene en el clculo de la cota superior del coste de los algoritmossobre grafos.

  • - Borrar una arista del grafo: borra(g, u, v) devuelve el grafo g' definido como: dom(g') = dom(g) - {}. u',v': dom(g'): g'(u', v') = g(u', v').

    - Consultar la etiqueta asociada a una arista del grafo: etiqueta(g, u, v), devuelve g(u, v) sidom(g), y en caso contrario.

    - Obtener el conjunto de vrtices a los cuales llega una arista desde uno dado, llamadossucesores (ing., successor ), juntamente con su etiqueta: suc(g, u) devuelve elconjunto recorrible sP(V x E ), tal que v : v V : dom(g) s.

    - Obtener el conjunto de vrtices de los cuales sale una arista a uno dado, llamadospredecesores (ing., predecessor), juntamente con su etiqueta: pred(g, v) devuelve elconjunto recorrible sP(V x E ), tal que v : v V : dom(g) s.

    Notemos, pues, que el modelo de los grafos dirigidos etiquetados es casi idntico al de lasrelaciones binarias valoradas y esto se refleja en la especificacin algebraicacorrespondiente, que consiste en una instancia de las relaciones, asociando el tipo de losvrtices a los dos gneros que definen la relacin y el tipo de las etiquetas como valor de larelacin; los vrtices sern un dominio con una relacin de orden

  • En cuanto al resto de modelos, hay pocos cambios en la especificacin. En los grafos noetiquetados desaparece el universo de caracterizacin de las etiquetas y, en consecuencia,la operacin etiqueta, sustituida por la operacin existe?: grafo vrtice vrtice bool, queresponde si dos vrtices estn directamente unidos o no por una arista. Por lo que respectaa los grafos no dirigidos, hay que establecer una relacin de conmutatividad de los dosvrtices parmetros de aade. Por otro lado, la distincin entre sucesores y predecesores deun vrtice no tiene sentido y se sustituye por el concepto ms general de adyacencia (ing.,adjacency): en un grafo no dirigido, dos vrtices son adyacentes si hay una arista que losune.

    Una caracterstica comn a todos estos modelos de grafo es que el conjunto de sus vrticeses fijo; no obstante, ocasionalmente puede interesar que sea un subconjunto W, W V,que pueda crecer y menguar durante la existencia del grafo. Esta variacin introduce uncambio en el modelo porque a las operaciones del tipo habr que aadir dos ms para ponery sacar vrtices del grafo, y otra para comprobar su presencia. La construccin precisa delmodelo, as como su especificacin e implementacin, quedan como ejercicio para el lector.

    Por ltimo, antes de comenzar a estudiar implementaciones y algoritmos, definimos diversosconceptos a partir del modelo tiles en secciones posteriores (la especificacin algebraica delos mismos se propone en el ejercicio 6.1). Un camino (ing., path) de longitud s 0 dentro deun grafo g {f : V x V E } es una sucesin de vrtices v0...vs, vi V, tales que hay una aristaentre todo par consecutivo de nodos de la secuencia. Dado el camino v0...vs,diremos que sus extremidades son v0 y vs, y al resto de vrtices los denominaremosintermedios . Igualmente, diremos que es propio (ing., proper) si s > 0; que es abierto siv0 vs, o cerrado en caso contrario; que es simple si no pasa dos veces por el mismo vrtice(exceptuando la posible igualdad entre extremidades) y que es elemental si no pasa dosveces por el mismo arco (un camino simple es forzosamente elemental). Por otro lado, elcamino w0...wr es subcamino (ing., subpath) del camino v0...vs si est incluido en l, es decir,si se cumple la propiedad: i: 0 i s - r -1: v0...vs = v0...viw0...wrvi+r+2...vs. Notemos quetodas estas definiciones son independientes de si el grafo es o no dirigido y de si es o noetiquetado.

    Dado un grafo g {f : V x V E }, diremos que dos vrtices v,w V estn conectados siexiste algn camino dentro de g que tenga como extremidades v y w; el sentido de laconexin es significativo si el grafo es dirigido. Si todo par de vrtices de V est conectadodiremos que g es conexo (ing., connected); en caso de grafos dirigidos, requeriremos laconexin de los vrtices en los dos sentidos y hablaremos de un grafo fuertemente conexo(ing., strongly connected). Definimos un componente conexo (ing., connected component ;fuertemente conexo en el caso dirigido) del grafo g o, simplemente, componente, como unsubgrafo de g conexo maximal (es decir, que no forma parte de otro subgrafo conexo de g);un grafo g' {f : V x V E } es subgrafo de g si dom(g' ) dom(g) y adems, en caso de seretiquetado, se cumple que : dom(g'): g'(u, v) = g(u, v).

    Relaciones binarias y grafos 3 1 9__________________________________________________________________________________

  • a b

    c

    d e

    f g

    h

    a b c b d e es camino propio abierto no elementala b d e f g es camino propio abierto simplea b d e f d es camino propio abierto elemental no simplea b d g no es camino

    Fig. 6.7: estudio de la existencia de caminos en un grafo.

    En un grafo dirigido, un ciclo (ing., cycle) es un camino cerrado propio. Si, adems, el caminono contiene ningn subcamino cerrado propio, entonces se denomina ciclo elemental . Deforma simtrica, diremos que el ciclo A es un subciclo del ciclo B si A es un subcamino de B.En el caso de grafos no dirigidos, es necesario evitar ciclos de la forma vw...wv (es decir,caminos que vuelven al principio pasando por la misma arista de salida); por tanto, haremoslas siguientes precisiones:

    - El camino A = v0v1...vn-1vn es simplificable si v0 = vn y v1 = vn-1, y su simplificacin es elcamino v0.

    - La simplificacin extendida de un camino es la sustitucin de todo sus subcaminossimplificables por la simplificacin correspondiente.

    - Un ciclo es un camino cerrado propio A tal que su simplificacin extendida sigue siendoun camino cerrado propio. Si, adems, la simplificacin extendida de A no contieneningn subcamino cerrado propio, entonces el ciclo se denomina ciclo elemental .Diremos que el ciclo A = v0...v0 es un subciclo del ciclo B si A es un subcamino de B.

    B C

    A

    2 3

    1

    A no es un ciclo 1 no es un cicloA B no es un ciclo 1 2 1 no es un cicloB C B es un ciclo elemental 1 2 3 1 es un ciclo elementalB C B C B es un ciclo no elemental 1 2 3 2 1 no es un ciclo

    Fig. 6.8: estudio de la existencia de ciclos en un grafo.

    3 2 0 Estructuras de datos. Especificacin, diseo e implementacin __________________________________________________________________________________

  • 6.2.2 Implementacin

    Estudiaremos tres tipos de implementaciones para grafos dirigidos y etiquetados; laextensin al resto de casos es inmediata y se comenta brevemente al final de la seccin.Consideramos que los vrtices se pueden usar directamente para indexar vectores8 yobtenerlos uno detrs de otro en un bucle "para todo" mediante las operaciones definidasen ELEM_ORDENADO (v. fig. 5.30)..

    a) Implementacin por matriz de adyacenciaDado g un grafo dirigido y etiquetado definido sobre un dominio V de vrtices y conetiquetas de tipo E, g {f : V x V E }, definimos una matriz bidimensional M, indexada porpares de vrtices, que almacena en cada posicin M [u, v] la etiqueta de la arista que une u yv . Si entre los vrtices u y v no hay ninguna arista, el valor de M [u, v] es el valor indefinido delas aristas (de acuerdo con la especificacin del tipo); si la especificacin no considera laexistencia de este valor especial, se requiere aadir a cada posicin un campo booleano quemarque la ausencia de arista.

    1 5 2

    3

    22

    4

    A B C D

    A

    B

    C

    D

    B

    A

    C

    D

    1

    3

    4

    2 2

    2

    5

    Fig. 6.9: un grafo y su implementacin por matriz de adyacencia.

    En la fig. 6.10 se muestra una posible implementacin de esta estrategia. Notemos el usoimplcito de las instancias de los pares y de los conjuntos recorribles, formuladas en laespecificacin de las relaciones y renombradas en la especificacin de los grafos. Por suparte, el invariante simplemente confirma la inexistencia de aristas de un vrtice a s mismo, locual obliga a que las posiciones de la diagonal principal valgan . Como esta representacinexige comparar etiquetas, el universo de caracterizacin correspondiente esELEM_ESP_=, similar a ELEM_2_ESP_= (v. fig. 4.18) pero con una nica constante esp. Laordenacin de los elementos en suc y pred coincide con el recorrido ordenado de las filas ycolumnas de la matriz.

    Relaciones binarias y grafos 3 2 1__________________________________________________________________________________

    8 Si no, sera necesario usar el TAD tabla como alternativa a los vectores; segn la eficiencia exigida,la tabla se podra implementar posteriormente por dispersin, rboles de bsqueda o listas.

  • universo DIGRAFO_ETIQ_MATRIZ(V es ELEM_ORDENADO, E es ELEM_ESP_=) esimplementa DIGRAFO_ETIQ(V es ELEM_
  • El coste temporal de la representacin, suponiendo una buena implementacin de losconjuntos recorribles (v. seccin 4.5), queda: crea es (n 2), las operaciones individualessobre aristas son (1) y tanto suc como pred quedan (n), independientemente de cuntossucesores o predecesores tenga el nodo en cuestin. As, el coste de consultar todas lasaristas del grafo es (n 2). El coste espacial de la estructura es considerable, (n 2).

    b) Implementacin por listas de adyacenciaPara un grafo g dirigido y etiquetado, definido sobre un dominio V de vrtices y conetiquetas de tipo E, g {f : V x V E }, se asocia a cada vrtice una lista con sus sucesores;para acceder al inicio de estas listas, se usa un vector indexado por vrtice.

    B1

    C5

    D2A

    B

    C

    D

    D3

    A2

    D2

    B4

    Fig. 6.11: implementacin del grafo de la fig. 6.9 por listas de adyacencia.

    Para que la implementacin sea correcta respecto la especificacin, deben ordenarse laslistas de sucesores usando la operacin

  • inicial). El invariante del grafo confirma de nuevo la ausencia de aristas de un vrtice a smismo con una variante de la tpica funcin cadena, que se define usando operaciones delTAD lista; las listas cumplirn su propio invariante (en concreto, el criterio de ordenacin delos elementos). El universo introduce una funcin auxiliar, busca, que devuelve un booleanoindicando si un elemento dado est dentro de una lista o no y, en caso afirmativo, coloca elpunto de inters sobre l; gracias a esta funcin, evitamos algn recorrido redundante de lalista ordenada.

    universo DIGRAFO_ETIQ_LISTAS(V es ELEM_ORDENADO, E es ELEM_ESP) esimplementa DIGRAFO_ETIQ(V es ELEM_

  • funcin borra (g es grafo; v, w son vrtice) devuelve grafo esvar est? es bool fvar

    := busca(g[v], w)si est? entonces g[v] := LISTA_INTERS_ORDENADA.borra_actual(g[v]) fsi

    devuelve g

    funcin etiqueta (g es grafo; v, w son vrtice) devuelve etiq esvar est? es bool; et es etiq fvar

    := busca(g[v], w)si est? entonces et := LISTA_INTERS_ORDENADA.actual(g[v]).et si no et := indef fsi

    devuelve et

    funcin suc (g es grafo; v es vrtice) devuelve cjt_vrtices_y_etiqs esvar w es vrtice; s es cjt_vrtices_y_etiqs fvar

    s := crea

    para todo w dentro de vrtice hacer s := aade(s, actual(g[w])) fpara tododevuelve s

    funcin pred (g es grafo; v es vrtice) devuelve cjt_vrtices_y_etiqs esvar w es vrtice; est? es bool; s es cjt_vrtices_y_etiqs fvar

    s := crea

    para todo w dentro de vrtice hacer := busca(g[w], v)si est? entonces s := aade(s, ) fsi

    fpara tododevuelve s

    {Funcin auxiliar busca(l, v)

  • Dado el coste constante de las operaciones sobre listas con el punto de inters como mediode referencia y el coste lineal de suprimir un elemento de una lista ordenada, y suponiendode nuevo una buena representacin para los conjuntos recorribles, la eficiencia temporal dela representacin presenta las siguientes caractersticas:

    - crea queda (n).- Las operaciones individuales sobre aristas dejan de ser constantes porque ahora es

    necesario buscar un elemento en la lista de sucesores de un nodo. El coste es, pues,(k ), siendo k el nmero estimado de aristas que saldrn de un nodo; este coste seconvierte en (n) en el caso peor.

    - La operacin suc queda (k ), que mejora en el caso medio la eficiencia de laimplementacin por matrices, porque los nodos sucesores estn siempre calculadosen la misma representacin del grafo. No obstante, el caso peor sigue siendo (n).

    - Finalmente, pred queda (a+n) en el caso peor; el factor a surge del examen de todaslas aristas (si el vrtice no tiene ningn predecesor), mientras que n se debe al hechode que, si el grafo presenta menos aristas que nodos, el tiempo de examen del vectorndice pasa a ser significativo. El caso mejor no bajar, pues, de (n).

    Es decir, excepto la creacin (que normalmente no influye en el estudio de la eficiencia) ysuc, el coste temporal parece favorecer la implementacin por matriz. Ahora bien,precisamente el buen comportamiento de suc hace que muchos de los algoritmos que sepresentan en el captulo sean ms eficientes con una implementacin por listas, porque sebasan en un recorrido de todas las aristas del grafo que se pueden obtener en (a+n), frenteal coste (n2) de las matrices, siendo 0 a n 2 - n.

    El coste espacial es claramente (a+n) que, como mucho, es asintticamente equivalente alespacio (n 2) requerido por la representacin matricial, pero que en grafos dispersos queda(n). Ahora bien, es necesario tener en cuenta que el espacio para los encadenamientospuede no ser despreciable porque, generalmente, las etiquetas sern enteros y cada celdade las listas ocupar relativamente ms que una posicin de la matriz de adyacencia; engrafos densos, el coste real puede incluso contradecir los resultados asintticos (v. ejercicio6.5). Debe notarse tambin que, si los vrtices no son un tipo escalar, no slo debesustituirse el vector ndice por una tabla, sino que tambin es necesario sustituir el campovrtice por un apuntador a una entrada de la tabla en las listas, si se quiere evitar laredundancia de la informacin. No obstante, esta opcin obliga a conocer la representacinelegida para la tabla, motivo por el cual no es posible usar directamente instancias de los tiposgenricos, pues se violaran las reglas de transparencia de la informacin propuesta en eltexto. Estos comentarios tambin son vlidos para la representacin que estudiamos acontinuacin.

    3 2 6 Estructuras de datos. Especificacin, diseo e implementacin __________________________________________________________________________________

  • c) Implementacin por multilistas de adyacenciaYa se ha comentado la extrema ineficiencia de la funcin pred en el esquema de listas deadyacencia. Si se necesita que esta operacin sea lo ms rpida posible, se puede repetir laestrategia anterior, pero sustituyendo las listas de sucesores por listas de predecesores, loque hace que suc sea ineficiente. Ahora bien, si se exige que suc sea tambin eficiente,deben asociarse dos listas a cada vrtice, la de sus sucesores y la de sus predecesores. Enrealidad esta solucin corresponde al concepto de multilista de grado dos usada paraimplementar las relaciones binarias entre dos conjuntos cualesquiera de elementos. En elcaso de los grafos, la relacin binaria se establece entre elementos de un mismo conjunto,pero este hecho no afecta al esquema general.

    En la fig. 6.14 se ofrece una implementacin instanciando el TAD de las relaciones valoradas;notemos que, al contrario de la estrategia anterior, no se obliga a representar las multilistas deuna manera concreta, porque las diversas implementaciones que de ellas existen ya seocupan de optimizar espacio, y ser el usuario del grafo quien escoger la estrategiaadecuada en su contexto (listas circulares, con identificadores en las celdas, etc.). Elinvariante establece, una vez ms, la antirreflexividad de la relacin. La eficiencia de lasoperaciones queda como en el caso anterior, excepto pred, que mejora por los mismosrazonamientos que suc. Espacialmente, el coste asinttico tampoco cambia, aunque debeconsiderarse que ahora el vector ndice ocupa el doble y que tambin hay el doble deencadenamientos en las celdas (o ms, segn la representacin de las multilistas).

    1 5A

    B

    C

    D

    2

    3

    2 2

    4

    AB AC AD

    BD

    CD

    DB

    CA

    Fig. 6.13: implementacin del grafo de la fig. 6.9 por multilistas de adyacencia.

    Relaciones binarias y grafos 3 2 7__________________________________________________________________________________

  • universo DIGRAFO_ETIQ_MULTILISTAS(V es ELEM_ORDENADO, E es ELEM_ESP) esimplementa DIGRAFO_ETIQ(V es ELEM_
  • 6.3 Recorridos de grafos

    Con frecuencia, los programas que trabajan con grafos precisan aplicar sistemticamente untratamiento a todos los vrtices que forman parte de los mismos (es decir, se visitan todos losvrtices del grafo). A veces no importa el orden de obtencin de los nodos y es suficiente unbucle "para todo" sobre el tipo de los vrtices, a veces se necesita imponer una poltica derecorrido que depende de las aristas existentes. El segundo caso conduce al estudio dediversas estrategias de recorrido de grafos que se presentan en esta seccin; como nodependen de si el grafo est etiquetado o no, consideramos el segundo caso.

    Por analoga con los rboles, distinguimos diferentes recorridos en profundidad, unrecorrido en anchura y el llamado recorrido por ordenacin topolgica . Todos ellos usanconjuntos para almacenar los vrtices visitados en cada momento porque, a diferencia de losrboles, puede accederse a un mismo nodo siguiendo diferentes caminos y deben evitarselas visitas reiteradas. Las operaciones sobre estos conjuntos sern la constante conjuntovaco, aadir un elemento y comprobar la pertenencia y, por ello, nos basaremos en lasignatura presentada en la fig. 1.29, definiendo una operacin ms, , como . Por lo querespecta a la implementacin, supondremos que las operaciones son de orden constante(por ejemplo, usando un vector de booleanos indexado por el tipo de los vrtices).

    Para fijar la signatura definimos los recorridos como funciones recorrido: grafo lista_vrtice,siendo lista_vrtice el resultado de instanciar las listas con punto de inters con el tipo de losvrtices. Se podra considerar la alternativa de introducir operaciones de obtencin de losvrtices uno a uno segn las diferentes estrategias; el resultado sera el tipo de los grafoscon punto de inters, definibles de manera similar a los rboles. Igualmente, una variantehabitual consiste en incluir la visita de los vrtices dentro del recorrido de manera que no seanecesario construir primero una lista y despus recorrerla; la eficiencia de esta opcin chocafrontalmente con la modularidad de los enfoques anteriores. Una poltica diferente quepodemos encontrar en diversas fuentes bibliogrficas consiste en sustituir la lista por unvector indexado por vrtices de modo que en cada posicin residir el ordinal de visita.Notemos que esta versin es un caso particular de devolver una lista y como tal se podraobtener efectuando las instancias oportunas. Ahora bien, debemos destacar que elalgoritmo resultante permite eliminar el conjunto de vrtices ya visitados, previa inicializacindel vector a un valor especial; por otra parte, no es posible un recorrido ordenado rpidoposterior del vector, porque es necesario ordenarlo antes.

    Tanto en esta seccin como en las siguientes nos centraremos en el estudio de losalgoritmos y no en su encapsulamiento dentro de universos. Por ejemplo, escribiremos laspre- y postcondiciones y los invariantes de los bucles especialmente interesantes, ysupondremos que todas las instancias necesarias de conjuntos, colas, listas, etc., han sidoformuladas previamente en alguna parte, explicitando las implementaciones que respondena los requerimientos de eficiencia pedidos. Por lo que respecta al encapsulamiento, tan slo

    Relaciones binarias y grafos 3 2 9__________________________________________________________________________________

  • decir que hay tres opciones principales:- Encerrar cada algoritmo individualmente dentro de un universo: el resultado sera un

    conjunto de mdulos muy grande, seguramente difcil de gestionar y por ello poco til.- Encerrar todos los algoritmos referidos a un mismo modelo de grafo en un nico

    universo: si bien facilita la gestin de una hipottica biblioteca de tipos de datos, hayque tener presente que diferentes algoritmos pueden exigir diferentes propiedadesde partida sobre los grafos (que sean conexos, que no haya etiquetas negativas, etc.).

    - Encerrar todos los algoritmos del mismo tipo y referidos a un mismo modelo de grafo enun nico universo: parece la opcin ms equilibrada, porque todos los algoritmosorientados a resolver una misma clase de problemas requieren propiedades muysimilares o idnticas sobre el grafo de partida.

    6.3.1 Recorrido en profundidad

    El recorrido de bsqueda en profundidad (ing., depth-first search ; algunos autores aadenel calificativo "prioritaria") o, simplemente, recorrido en profundidad , popularizado porJ.E. Hopcroft y R.E. Tarjan el ao 1973 en "Efficient algorithms for graph manipulation",Communications ACM, 16(6), pp. 372-378, es aplicable indistintamente a los grafos dirigidosy a los no dirigidos, considerando en el segundo caso cada arista no dirigida como un par dearistas dirigidas. El procedimiento es una generalizacin del recorrido preorden de un rbol:se comienza visitando un nodo cualquiera y, a continuacin, se recorre en profundidad elcomponente conexo que "cuelga" de cada sucesor (es decir, se examinan los caminos hastaque se llega a nodos ya visitados o sin sucesores); si despus de haber visitado todos lossucesores transitivos del primer nodo (es decir, l mismo, sus sucesores, los sucesores desus sucesores, y as sucesivamente) todava quedan nodos por visitar, se repite el proceso apartir de cualquiera de estos nodos no visitados. En el resto de la seccin, a los sucesorestransitivos de un nodo los llamaremos descendientes y, simtricamente, a los predecesorestransitivos los llamaremos antecesores ; su especificacin se propone en el ejercicio 6.1.

    El recorrido en profundidad tiene diferentes aplicaciones. Por ejemplo, se puede usar paraanalizar la robustez de una red de computadores representada por un grafo no dirigido (v.[AHU83, pp. 243-245]). Tambin se puede utilizar para examinar si un grafo dirigido presentaalgn ciclo, antes de aplicar sobre l cualquier algoritmo que exija que sea acclico.

    La especificacin del recorrido se estudia en el ejercicio 6.31. A la vista de la descripcindada queda claro que, en realidad, no hay un nico recorrido en profundidad prioritaria de ungrafo, sino un conjunto de recorridos, todos ellos igualmente vlidos, y por ello no seespecifica el procedimiento de construccin de una solucin, sino un predicado quecomprueba si una lista de vrtices es un recorrido vlido para un grafo; generalmente, estaindeterminacin no causa ningn problema en la aplicacin que necesita el recorrido9. Al

    3 3 0 Estructuras de datos. Especificacin, diseo e implementacin __________________________________________________________________________________

    9 Podra obligarse a empezar cada recorrido de un nuevo componente por un nodo sin predecesores.

  • contrario que los rboles, el indeterminismo es una caracterstica comn a todas lasestrategias de recorridos sobre grafos.

    En la fig. 6.15 se presenta un algoritmo recursivo de recorrido en profundidad prioritaria, queusa un conjunto S para almacenar los vrtices ya visitados, y un procedimiento auxiliar pararecorrer recursivamente todos los descendientes de un nodo (includo l mismo); suresultado es la lista de los vrtices en orden de visita. Tal como establece el invariante, loselementos de la lista resultado y de S son siempre los mismos, pero el conjunto se mantienepara poder comprobar rpidamente si un vrtice ya est en la solucin. En el invariante se usala operacin subgrafo, cuya especificacin se propone en el ejercicio 6.1. La transformacinde este algoritmo en iterativo queda como ejercicio para el lector.

    {P g es un grafo dirigido y no etiquetado}funcin recorrido_en_profundidad (g es grafo) devuelve lista_vrtices esvar S es cjt_vrtices; v es vrtice; l es lista_vrtices fvar

    S := ; l := LISTA_INTERS.creapara todo v dentro de vrtice hacer

    {I es_recorrido_profundidad(l, subgrafo(g, S)) u: uvrtice: (ul uS) (ul w: wdescendientes(g, u): wl ) }

    si v S entonces visita_componente(g, v, S, l) fsifpara todo

    devuelve l{Q es_recorrido_profundidad(l, g)} -- v. ejercicio 6.31{P v S es_recorrido_profundidad(l, subgrafo(g, S))

    u: uvrtice: (ul uS) (ul w: wdescendientes(g, u): wl )}accin privada visita_componente (ent g es grafo; ent v es vrtice;

    ent/sal S es cjt_vrtices; ent/sal l es lista_vrtices) esvar w es vrtice fvar

    S := S {v}; l := LISTA_INTERS.inserta(l, v){visita de todos los descendientes de v}

    para todo w dentro de suc(g, v) hacer{I es_recorrido_profundidad(l, subgrafo(g, S))

    u: uvrtice: (ul uS) (ul u v w: wdescendientes(g, u): wl ) }si w S entonces visita_componente(g, w, S, l) fsi

    fpara todofaccin{Q v S es_recorrido_profundidad(l, subgrafo(g, S))

    u: uvrtice: (ul uS) (ul w: wdescendientes(g, u): wl )}

    Fig. 6.15: algoritmo del recorrido en profundidad prioritaria.

    Relaciones binarias y grafos 3 3 1__________________________________________________________________________________

  • El recorrido en profundidad estndar se puede modificar adoptando justamente el enfoquesimtrico, sin visitar un nodo hasta haber visitado todos sus descendientes, en lo que sepuede considerar como la generalizacin del recorrido postorden de un rbol. Diversostextos denominan a este recorrido recorrido en profundidad con numeracin hacia atrs o,simplemente, recorrido en profundidad hacia atrs (ing., backward depth-first search); por elmismo motivo, el recorrido en profundidad estudiado hasta ahora tambin se denominarecorrido en profundidad hacia delante (ing., forward depth-first search). En la fig. 6.16 sepresenta un ejemplo para ilustrar la diferencia. Por lo que respecta al algoritmo de la fig. 6.15,simplemente sera necesario mover la insercin de un nodo a la lista tras el bucle.

    A B C1,6 2,4 3,2

    D E F

    6,5 5,3 4,1

    Fig. 6.16: numeracin de los vrtices de un grafo en un recorrido en profundidadiniciado en A (izquierda: hacia delante; derecha: hacia atrs) considerando

    el orden alfabtico para resolver indeterminaciones.

    El coste temporal del algoritmo depende exclusivamente de la implementacin elegida parael grafo. Usando una representacin por listas o multilistas de adyacencia obtenemos (a+n),porque, dado un vrtice, siempre se consultan las aristas que de l parten, aunque no sevisite ms que una vez; el factor n aparece por si el grafo tiene menos aristas que vrtices. Sise hace la representacin mediante matriz de adyacencia el coste es (n2), por culpa deltiempo lineal de la operacin suc ; es decir, si el grafo es disperso, la representacin por listases ms eficiente por la rapidez en la obtencin de todas las aristas del grafo. Por lo querespecta al espacio adicional empleado, es lineal sobre el nmero de nodos debido alconjunto.

    6.3.2 Recorrido en anchura

    El recorrido de bsqueda en anchura o expansin (ing., breadth-first search) o,simplemente, recorrido en anchura es otra estrategia aplicable indistintamente al caso degrafos dirigidos y no dirigidos, que generaliza el concepto de recorrido por niveles de unrbol: despus de visitar un vrtice se visitan los sucesores, despus los sucesores de lossucesores, despus los sucesores de los sucesores de los sucesores, y as reiteradamente.

    3 3 2 Estructuras de datos. Especificacin, diseo e implementacin __________________________________________________________________________________

  • Si despus de visitar todos los descendientes del primer nodo todava quedan ms nodospor visitar, se repite el proceso. La especificacin de este recorrido se propone tambin en elejercicio 6.31.

    Una aplicacin tpica del recorrido en anchura es la resolucin de problemas de planificacin,donde se dispone de un escenario que se puede modelizar mediante un estado. El estadorepresenta la configuracin de un conjunto de elementos de manera que, si cambia sudisposicin o nmero, cambia el estado; los cambios de estado atmicos (es decir, que no sepueden considerar como la composicin de otros cambios ms simples) se denominantransiciones. En estas condiciones, una cuestin habitual consiste en determinar lasecuencia ms corta de transiciones que lleva de un estado inicial a un estado final, y lapregunta se puede contestar en trminos de un recorrido en expansin de un grafo. Dehecho, en 1959 E.F. Moore introdujo el recorrido en anchura en este contexto, como unaayuda para atravesar un laberinto ("The shortest path through a maze", en Proceedings ofthe International Symposium on the Theory of Switching, Harvard Univesity Press). En elapartado 7.1.3 se resuelve este problema para una situacin concreta.

    El algoritmo sobre grafos dirigidos (v. fig. 6.17) utiliza una cola para poder aplicar la estrategiaexpuesta. Notemos que el procedimiento principal es idntico al del recorrido enprofundidad prioritaria y que visita_componente es similar al anterior usando una cola devrtices10. Asmismo observemos que hay que marcar un vrtice (es decir, insertarlo en elconjunto S ) antes de meterlo en la cola, para no encolarlo ms de una vez. El invariante delprocedimiento auxiliar obliga a que todos los elementos entre v y los que estn en la cola(pendientes de visita) ya hayan sido visitados, y a que todos los elementos ya visitadostengan sus sucesores, o bien visitados, o bien en la cola para ser visitados de inmediato.

    Los resultados sobre la eficiencia son idnticos al caso del recorrido en profundidad.

    6.3.3 Recorrido en ordenacin topolgica

    La ordenacin topolgica (ing., topological sort) es un recorrido solamente aplicable a grafosdirigidos acclicos, que cumple la propiedad de que un vrtice slo se visita si han sidovisitados todos sus predecesores dentro del grafo. De esta manera, las aristas definen unarestriccin ms fuerte sobre el orden de visita de los vrtices.

    La aplicacin ms habitual del recorrido en ordenacin topolgica aparece cuando losvrtices del grafo representan tareas y las aristas relaciones temporales entre ellas. Porejemplo, en el plan de estudios de una carrera universitaria cualquiera, puede haberasignaturas con la restriccin de que slo se puedan cursar si previamente se han aprobado

    Relaciones binarias y grafos 3 3 3__________________________________________________________________________________

    10 De hecho, la transformacin en iterativo del procedimiento visita_componente del recorrido enprofundidad da el mismo algoritmo sustituyendo la cola por una pila.

  • otras, llamadas prerrequisitos. Este plan de estudios forma un grafo dirigido, donde losnodos son las asignaturas y existe una arista de la asignatura A a la asignatura B, si y slo siA es prerrequisito de B. Notemos, adems, que el grafo ha de ser acclico: si A esprerrequisito de B (directa o indirectamente) no debe existir ninguna secuencia deprerrequisitos que permitan deducir que B es prerrequisito de A (directa o indirectamente).

    {P g es un grafo dirigido no etiquetado}funcin recorrido_en_anchura (g es grafo) devuelve lista_vrtices esvar S es cjt_vrtices; v es vrtice; l es lista_vrtices fvar

    S := ; l := LISTA_INTERS.creapara todo v dentro de vrtice hacer

    {I es_recorrido_anchura(l, subgrafo(g, S)) u: uvrtice: (ul uS) (ul w: wdescendientes(g, u): wl ) }

    si v S entonces visita_componente(g, v, S, l) fsifpara todo

    devuelve l{Q es_recorrido_anchura(l, g)} -- v. ejercicio 6.31

    {P v S es_recorrido_anchura(l, subgrafo(g, S)) u: uvrtice: (ul uS) (ul w: wdescendientes(g, u): wl)}

    accin privada visita_componente (ent g es grafo; ent v es vrtice;ent/sal S es cjt_vrtices; ent/sal l es lista_vrtices) es

    var c es cola_vrtices; u, w son vrtice fvarS := S {v}; c := COLA.encola(COLA.crea, v)mientras COLA.vaca?(c) hacer

    {I es_recorrido_anchura(l, subgrafo(g, S)) (u: uvrtice: ul uS) (u: uc: w: wascendientes(g, u)-{u}: wdescendientes(g, v) wl ) (u: ul: w: wsuc(g, u): wl wc) }

    w := COLA.cabeza(c); c := COLA.desencola(c)l := LISTA_INTERS.inserta(l, w)para todo u dentro de suc(g, v) hacer

    si u S entonces S := S {u}; c := COLA.encola(c, u) fsifpara todo

    fmientrasfacci{Q v S es_recorrido_anchura(l, subgrafo(g, S))

    u: uvrtice: (ul uS) (ul w: wdescendientes(g, u): wl)}

    Fig. 6.17: algoritmo de recorrido en anchura de un grafo dirigido.

    3 3 4 Estructuras de datos. Especificacin, diseo e implementacin __________________________________________________________________________________

  • Cuando un alumno se matricula en este plan de estudios, ha de cursar diversas asignaturas(es decir, ha de recorrer parte del grafo del plan de estudios) respetando las reglas:

    - Al comenzar, slo puede cursar las asignaturas (es decir, visitar los nodos) que notengan ningn prerrequisito (es decir, que no tengan ningn predecesor en el grafo).

    - Slo se puede cursar una asignatura si han sido cursados todos sus prerrequisitospreviamente (es decir, si han sido visitados todos sus predecesores).

    As, pues, un estudiante se licencia cuando ha visitado un nmero suficiente de nodosrespetando estas reglas, las cuales conducen a un recorrido en ordenacin topolgica.

    IP Alg

    EC-I PM

    LGAEDA

    MD

    Fig. 6.18: parte del plan de estudios de la Ingeniera en Informtica impartida en laFacultat d'Informtica de Barcelona de la Universitat Politcnica de Catalunya.

    La descripcin del funcionamiento del algoritmo se presenta en la fig. 6.19: se vanescogiendo los vrtices sin predecesores, que son los que se pueden visitar y, a medidaque se incorporan a la solucin se borran las aristas que salen de ellos; la funcin nodos delinvariante devuelve todos los elementos pertenecientes a una lista. Los recorridosobtenidos de esta forma responden a la especificacin que se propone en el ejercicio 6.31.

    {P g es un grafo dirigido no etiquetado y acclico} funcin ordenacin_topolgica (g es grafo) devuelve lista_vrtices esvar l es lista_vrtices; v, w son vrtices fvar

    l := LISTA_INTERS.creamientras queden nodos por visitar hacer

    {I es_ordenacin_topolgica(l, subgrafo(g, nodos(l))) }escoger v l tal que todos sus predecesores estn en ll := LISTA_INTERS.inserta(l, v)

    fmientrasdevuelve l{Q es_ordenacin_topolgica(l, g)} -- v. ejercicio 6.31

    Fig. 6.19: presentacin del algoritmo de ordenacin topolgica.

    Relaciones binarias y grafos 3 3 5__________________________________________________________________________________

  • Obviamente la implementacin directa de esta descripcin es costosa, ya que hay quebuscar vrtices sin predecesores repetidas veces. Una alternativa consiste en calcularpreviamente cuntos predecesores tiene cada vrtice, almacenar el resultado en un vector yactualizarlo siempre que se incorpore un nuevo vrtice a la solucin. En la fig. 6.20 sepresenta una implementacin de esta ltima opcin, que usa un vector de vrticesnm_pred, el cual asocia el nmero de predecesores que todava no estn en la solucin acada vrtice, y un conjunto ceros donde se guardan todos los vrtices que se puedenincorporar en el paso siguiente del algoritmo. La inicializacin de la estructura, ciertamenterebuscada a simple vista, est diseada para ser asintticamente ptima para cualquierrepresentacin del grafo; con este objetivo se evita el uso de la operacin etiqueta, queexige bsquedas lineales en caso de listas11. Ntese el uso de una operacin sobreconjuntos, escoger_uno_cualquiera, que devuelve un elemento cualquiera del conjunto ylo borra, y que debe ser ofrecida por la especificacin del TAD de los conjuntos o bien por unenriquecimiento.

    Para calcular el coste temporal del algoritmo se suman los costes de la inicializacin de lasestructuras y del bucle principal. En la inicializacin, el primer bucle queda (n), mientras queel segundo exige un examen de todas las aristas del grafo y queda, pues, (a+n) en el casode listas de adyacencia y (n2) en caso de matriz de adyacencia. En lo que respecta al bucleprincipal, un examen poco cuidadoso podra llevar a decir que es (n 2), dado que el bucle seejecuta n veces (en cada paso se aade un vrtice a la solucin) y en cada iteracin seobtienen los sucesores del nodo escogido, operacin que es (n) en el caso peor(supongamos que escoger_uno_cualquiera es de orden constante). Ahora bien, notemosque la iteracin interna exige, a lo largo del algoritmo, el examen de todas las aristas quecomponen el grafo con un tratamiento constante de cada una, lo que, en realidad, es (a) yno (n2) si el grafo est implementado por listas de adyacencia. Como la operacinescoger_uno_cualquiera se ejecuta un total de n-1 veces y es (1), se puede concluir quela eficiencia temporal del algoritmo es, una vez ms, (a+n) con listas de adyacencia y (n2)con matriz de adyacencia y, por ello, la representacin por listas de adyacencia es preferible siel grafo es disperso, mientras que si es denso la implementacin no afecta a la eficiencia.

    3 3 6 Estructuras de datos. Especificacin, diseo e implementacin __________________________________________________________________________________

    11 Otra opcin sera disponer de dos versiones del algoritmo en dos universos diferentes, una paraimplementacin mediante matriz y otra para listas o multilistas. No obstante, preferimos esta opcinpara simplificar el uso del algoritmo.

  • {P g es un grafo dirigido no etiquetado y acclico 12 }funcin ordenacin_topolgica (g es grafo) devuelve lista_vrtices esvar l es lista_vrtices; v, w son vrtice

    ceros es cjt_vrtices; nm_pred es vector [vrtice] de natfvar

    {inicializacin de las estructuras en dos pasos}ceros := para todo v dentro de vrtice hacer

    nm_pred[v] := 0; ceros := ceros {v}fpara todopara todo v dentro de vrtice hacer

    para todo w dentro de suc(g, v) hacernm_pred[w] := nm_pred[w] + 1; ceros := ceros - {w}

    fpara todofpara todo

    {a continuacin se visitan los vrtices del grafo}l := LISTA_INTERS.creamientras ceros hacer

    {I es_ordenacin_topolgica(l, subgrafo(g, nodos(l))) w: wvrtice: nm_pred[w] = ||{Ag / ul }||

    wceros nm_pred[w] = 0} := escoger_uno_cualquiera(ceros)l := LISTA_INTERS.inserta(l, v)para todo w dentro de suc(g, v) hacer

    nm_pred[w] := nm_pred[w] - 1si nm_pred[w] = 0 entonces ceros := ceros {w} fsi

    fpara todofmientras

    devuelve l{Q es_ordenacin_topolgica(l, g)}

    Fig. 6.20: implementacin del algoritmo de ordenacin topolgica.

    Relaciones binarias y grafos 3 3 7__________________________________________________________________________________

    12 Como alternativa, se podra controlar la condicin de aciclicidad del grafo en el propio algoritmo yentonces desaparecera de la precondicin.

  • 6.4 Bsqueda de caminos mnimos

    En esta seccin nos ocupamos de la bsqueda de caminos minimales dentro de grafosetiquetados no negativamente que sean lo ms cortos posible, donde la longitud de uncamino, tambin conocida como coste, se define como la suma de las etiquetas de las aristasque lo componen. Para abreviar, hablaremos de "suma de aristas" con significado "suma delas etiquetas de las aristas" y, por ello, hablaremos de "caminos mnimos" en vez de "caminosminimales". Concretamente, estudiamos un algoritmo para encontrar la distancia mnima deun vrtice al resto y otro para encontrar la distancia mnima entre todo par de vrtices.

    Dada la funcionalidad requerida, es necesario formular algunos requisitos adicionales sobreel dominio de las etiquetas, que se traducen en nuevos parmetros formales de losuniversos que encapsulen estos algoritmos. Concretamente, consideramos E como undominio ordenado, donde < es la operacin de ordenacin y = la de igualdad; para abreviar,usaremos tambin la operacin , definible a partir de stas. Tambin se precisa de unaoperacin conmutativa + para sumar dos etiquetas, que tiene una constante 0, a la cualdenominaremos etiqueta de coste nulo, como elemento neutro. Por ltimo, nos interesaque el valor indefinido esp represente la etiqueta ms grande posible, por motivos quequedarn claros a lo largo de la seccin; para mayor claridad, en los algoritmos que vienen acontinuacin supondremos que esp se renombra por . Las etiquetas negativas no formanparte del gnero, tal como establece la ltima propiedad del universo.

    universo ELEM_ESP_

  • 6.4.1 Camino ms corto de un nodo al resto

    Dado un grafo g {f : V x V E } con etiquetas no negativas, se trata de calcular el coste delcamino mnimo desde un vrtice dado al resto (ing., single-source shortest paths)13. Lautilidad de un procedimiento que solucione esta cuestin es clara: el caso ms habitual esdisponer de un grafo que represente una distribucin geogrfica, donde las aristas den elcoste (en precio, en distancia o similares) de la conexin entre dos lugares y sea necesarioaveriguar el camino ms corto para llegar a un punto partiendo de otro (es decir, determinar lasecuencia de aristas para llegar a un nodo a partir del otro con un coste mnimo).

    La solucin ms eficiente a este problema es el denominado algoritmo de Dijkstra, en honor asu creador, E.W. Dijkstra. Formulado en 1959 en "A note on two problems in connexion withgraphs", Numerical Mathematica, 1, pp. 269-271, sobre grafos dirigidos (su extensin al casono dirigido es inmediata y queda como ejercicio para el lector), el algoritmo de Dijkstra (v. fig.6.22) es un algoritmo voraz14 que genera uno a uno los caminos de un nodo v al resto pororden creciente de longitud; usa un conjunto S de vrtices donde, a cada paso delalgoritmo, se guardan los nodos para los que ya se sabe el camino mnimo y devuelve unvector indexado por vrtices, de manera que en cada posicin w se guarda el coste delcamino mnimo que conecta v con w. Cada vez que se incorpora un nodo a la solucin, secomprueba si los caminos todava no definitivos se pueden acortar pasando por l. Porconvencin, se supone que el camino mnimo de un nodo a s mismo tiene coste nulo. Unvalor infinito en la posicin w del vector indica que no hay ningn camino entre v y w.

    El invariante asegura que, en cada momento del algoritmo, el vector contiene caminosmnimos formados ntegramente por nodos de S (excepto el ltimo nodo), y que los nodosde S corresponden a los caminos mnimos ms cortos calculados hasta el momento. A talefecto, utiliza diversas funciones: caminos, que da el conjunto de caminos que se puedenencontrar dentro del grafo entre dos nodos; coste, que da el coste de un camino; mximo ymnimo, que dan los elementos mayor y menor de un conjunto, respectivamente. Laespecificacin de la primera se propone en el ejercicio 6.1; la especificacin de las otras essencilla y queda como ejercicio para el lector. Abusando de la notacin, se usa el operador deinterseccin entre un conjunto y un camino con el significado intuitivo.

    La especificacin del algoritmos se propone en el ejercicio 6.32, donde se generaliza elalgoritmo, pues el resultado es una tabla de vrtices y etiquetas; la versin de la fig. 6.22 esuna particularizacin de este caso, donde la tabla se implementa con un vector porque losvrtices son un tipo escalar; el caso general se propone en el mismo ejercicio.

    Relaciones binarias y grafos 3 3 9__________________________________________________________________________________

    13 Se podra pensar en el caso particular de encontrar el camino ms corto entre dos vrtices, pero elalgoritmo es igual de costoso que ste ms general.14 Los algoritmos voraces (ing., greedy) son una familia de algoritmos que se estructuran como unbucle que, en cada paso, calcula una parte ya definitiva de la solucin; para estudiar en profundidadsus caractersticas puede consultarse, por ejemplo, [BrB87].

  • {P g es un grafo dirigido etiquetado no negativamente}funcin Dijkstra (g es grafo; v es vrtice) devuelve vector [vrtice] de etiq esvar S es cjt_vrtices; D es vector [vrtice] de etiq fvar

    w: wvrtice: D[w] := etiqueta(g, v, w)D[v] := 0; S := {v}mientras S no contenga todos los vrtices hacer

    {I w: wvrtice: D[w] = mnimo({coste(C) / Ccaminos(g, v, w) C(S{w}) = C}) ( w: wS: D[w] < mximo({D[u] / uS}) }

    elegir w S tal que D[w] es mnimo; S := S {w}u: uS: actualizar distancia mnima comprobando si por w hay un atajo

    fmientrasdevuelve D{Q D = camino_mnimo(g, v)} -- v. ejercicio 6.32

    Fig. 6.22: descripcin del algoritmo de Dijkstra.

    {1}

    {1, 4}

    {1, 4, 3}

    {1, 4, 3, 5}

    1

    3

    2

    4

    5

    75 20 60

    2 30

    200 30

    0 20 60 75

    0 20 5022

    0 20 50222 22

    0 20 5080 22

    0 20 5080 22

    {1, 4, 3, 5, 2}

    D S

    Fig. 6.23: ejemplo de funcionamiento del algoritmo de Dijkstra, donde 1 es el nodo inicial.

    En la fig. 6.24 se detalla una posible codificacin del algoritmo. Notemos que el uso del valorindefinido de las etiquetas como la etiqueta ms grande posible permite denotar lainexistencia de caminos, porque cualquier camino entre dos nodos es ms pequeo que .Asmismo, notemos que el algoritmo no trabaja con el conjunto S sino con sucomplementario, T, que debe presentar operaciones de recorrido para aplicarle un bucle"para todo". El nmero n de vrtices es un parmetro formal ms, definido enELEM_ORDENADO. El bucle principal se ejecuta tan slo n-2 veces, porque el ltimocamino queda calculado despus del ltimo paso (no quedan vrtices para hallar atajos).

    3 4 0 Estructuras de datos. Especificacin, diseo e implementacin __________________________________________________________________________________

  • {P g es un grafo dirigido etiquetado no negativamente}funcin Dijkstra (g es grafo; v es vrtice) devuelve vector [vrtice] de etiq esvar T es cjt_vrtices; D es vector [vrtice] de etiq; u, w son vrtices fvar

    T := para todo w dentro de vrtice hacer

    D[w] := etiqueta(g, v, w); T := T {w}fpara todoD[v] := ETIQUETA.0; T := T - {v}hacer n-2 veces {quedan n-1 caminos por determinar}

    {I w: wvrtice: D[w] = mnimo({coste(C) / Ccaminos(g, v, w) (C-{w})T = }) ( w: wT: D[w] < mximo({D[u] / uT}) }

    {seleccin del mnimo w : wT (u: uT: D[w] D[u])}val := ETIQUETA.para todo u dentro de T hacer

    si D[u] val entonces w := u; val := D[u] fsi{como mnimo, siempre hay un nodo que cumple la condicin}

    fpara todo{se marca w como vrtice tractado}

    T := T - {w}{se recalculan las nuevas distancias mnimas}

    para todo u dentro de T hacersi D[w] + etiqueta(g, w, u) < D[u] entonces D[u] := D[w] + etiqueta(g, w, u) fsi

    fpara todofhacer

    devuelve D{Q D = caminos_mnimos(g, v)}

    Fig. 6.24: una codificacin posible del algoritmo de Dijkstra.

    Se analiza a continuacin el tiempo de ejecucin, suponiendo que las operaciones sobreconjuntos estn implementadas en tiempo constante, excepto la creacin (por ejemplo, yaprovechando que los vrtices son un tipo escalar, mediante un vector de booleanos).Distinguimos cuatro partes en el algoritmo: inicializacin, seleccin del mnimo, marcaje devrtices y reclculo de las distancias mnimas. Si la representacin es mediante matriz deadyacencia, la ejecucin de etiqueta es constante y se obtiene:

    - Inicializacin: creacin del conjunto y ejecucin n veces de diversas operacionesconstantes; queda (n).

    - Seleccin: las instrucciones del interior del bucle de seleccin son (1). Por lo querespecta al nmero de ejecuciones del bucle, en la primera vuelta se consultan n-1vrtices, en la segunda n-2, etc., ya que la dimensin de T decrece en una unidad en

    Relaciones binarias y grafos 3 4 1__________________________________________________________________________________

  • cada paso; es decir, a lo largo de las n-2 ejecuciones del bucle, sus instrucciones seejecutarn n(n-1)/2 - 1 veces y, as, la eficiencia total del paso de seleccin ser (n2).

    - Marcaje: n supresiones a lo largo del algoritmo conducen a (n).- Reclculo de las distancias mnimas: queda (n2) por los mismos razonamientos que el

    paso de seleccin.

    El coste total del algoritmo es la suma de las cuatro etapas, es decir, (n2).

    En la representacin por listas o multilista de adyacencias, lo nico que parece cambiar esque la operacin etiqueta deja de tener un coste constante. Ahora bien, un anlisis msexhaustivo demuestra que en realidad la sentencia "si ... fsi" del paso de reclculo slo setiene que ejecutar a veces a lo largo del algoritmo, si se sustituye el bucle sobre los vrticesde T por otro bucle sobre los vrtices del conjunto de sucesores de w (evitando el usoreiterado de etiq). Como siempre se cumple que a < n2, esta observacin puede sersignificativa, ya que, si tambin se consiguiera rebajar el coste del paso de seleccin, elalgoritmo de Dijkstra para grafos no densos representados con estructuras encadenadassera ms eficiente que la representacin mediante matriz.

    Para alcanzar este objetivo basta con organizar astutamente el conjunto de vrtices todavano tratados, teniendo en cuenta que se selecciona el elemento mnimo. Por ejemplo, sepuede sustituir el conjunto por una cola prioritaria, siendo sus elementos pares devrtice (todava no tratado) y etiqueta, que juega el papel de prioridad, con significado "ladistancia mnima de v a w es et" (et sera el valor D[w] de la fig. 6.22); las operaciones deobtencin y supresin del mnimo encajan perfectamente dentro del algoritmo. Ahora bien,el reclculo de las distancias del ltimo paso puede exigir cambiar la prioridad de un elementocualquiera de la cola. Por este motivo se define una nueva modalidad de cola con prioridadque permite el acceso directo a cualquier elemento y que, adems de las operacioneshabituales, incorpora tres ms: la primera, para cambiar la etiqueta asociada a un vrticecualquiera por una ms pequea, reorganizando la cola si es necesario; otra, para obtener elvalor asociado a un vrtice (que valdr si el vrtice no est en la cola); y una tercera, paracomprobar la presencia en la cola de un vrtice dado. En la fig. 6.26 se muestra la signaturaresultante de este tipo, aplicada al contexto del algoritmo, junto con su coste asinttico15, yen la fig. 6.25 se muestra un ejemplo de su funcionamiento suponiendo que, para mayoreficiencia, la cola se implementa con un montculo junto con un vector indexado por vrtices,de forma que cada posicin apunte al nodo del montculo que contenga la etiqueta asociadaal vrtice; la especificacin e implementacin del tipo quedan como ejercicio para el lector.

    3 4 2 Estructuras de datos. Especificacin, diseo e implementacin __________________________________________________________________________________

    15 En esta signatura se observa la ausencia de la funcin organiza de transformacin de un vector enuna cola (v. apartado 5.5.2), ms eficiente que la creacin de la cola por inserciones individuales.Dicha ausencia se debe a que el algoritmo queda ms claro sin que su coste asinttico se veaafectado. Si se considera conveniente, el algoritmo puede adaptarse fcilmente a esta modificacin.

  • 1234

    5

    (a) situacin inicial (b) despus de seleccionar el 4

    1

    234

    5

    12345

    12345

    (d) despus de seleccionar el 5(d) despus de seleccionar el 5

    Fig. 6.25: evolucin de la cola prioritaria aplicando el algoritmo sobre el grafo de la fig. 6.23.

    crea: colapr_aristas; (1)inserta: colapr_aristas vrtice etiq colapr_aristas; (logn)menor: colapr_aristas vrtice_y_etiq; (1)borra: colapr_aristas colapr_aristas; (logn)sustituye: colapr_aristas vrtice etiq colapr_aristas; (logn)valor: colapr_aristas vrtice etiq; (1)est?: colapr_aristas vrtice bool; (1)vaca?: colapr_aristas bool; (1)

    Fig. 6.26: signatura para las colas prioritarias extendidas con las operaciones necesarias.

    El algoritmo resultante se muestra en la fig. 6.27. La inicializacin requiere dos bucles paraevitar el uso de la operacin etiqueta. Se podra modificar el algoritmo para que las etiquetasinfinitas no ocupasen espacio en el montculo y mejorar as el tiempo de ejecucin de lasoperaciones que lo actualizan. El anlisis de la eficiencia temporal da como resultado:

    - La inicializacin es (k : 1 k n-1: log k ) + (nlogn) = (nlogn) + (nlogn) =(nlogn), dado que el paso k-simo del primer bucle ejecuta una insercin en una colade tamao k y todos los pasos del segundo bucle (n-1 como mximo) modifican unacola de tamao n.

    Relaciones binarias y grafos 3 4 3__________________________________________________________________________________

  • - Las n-1 selecciones del mnimo son constantes, y su supresin, logartmica sobre n, yqueda, pues, (n) + (k : 1 k n-1: log k ) = (n) + (nlogn) = (nlogn).

    - El bucle interno examina todas las aristas del grafo a lo largo del algoritmo y, en el casopeor, efecta una sustitucin por arista, de coste (logn), y as queda (a logn).

    En definitiva, el coste temporal es ((a+n)logn), mejor que la versin anterior si el grafo esdisperso; no obstante, si el grafo es denso, el algoritmo original es ms eficiente. El espacioadicional continua siendo asintticamente lineal sobre n.

    {P g es un grafo dirigido etiquetado no negativamente}funcin Dijkstra (g es grafo; v es vrtice) devuelve vector [vrtice] de etiq esvar D es vector [vrtice] de etiq; A es colapr_aristas; u, w son vrtices; et, val son etiq fvar

    {creacin de la cola con todas las aristas }A := COLA_EXTENDIDA.creapara todo w dentro de vrtice hacer A := COLA_EXTENDIDA.inserta(A, w, ) fpara todopara todo dentro de suc(g, v) hacer

    A := COLA_EXTENDIDA.modif(A, w, et)fpara todomientras COLAPR_EXTENDIDA.vaca?(A) hacer

    {I w: wvrtice: x = mnimo({coste(C) / Ccaminos(g, v, w) u: uC: u w est?(A, u)})

    menor(A).et mximo({D[u] / est?(A, u)}) definiendo x : est?(A, w) x = valor(A, w) est?(A, w) x = D[w] }

    := COLAPR_EXTENDIDA.menor(A) {seleccin de la arista mnima}D[w] := val; A := COLAPR_EXTENDIDA.borra(A) {marcaje de w como tratado}

    {reclculo de las nuevas distancias mnimas}para todo dentro de suc(g, w) hacer

    si COLAPR_EXTENDIDA.est?(A, u) entoncessi val+et < COLAPR_EXTENDIDA.valor(A, u) entonces

    A := COLAPR_EXTENDIDA.sustituye(A, u, val + et)fsi

    fsifpara todo

    fmientrasD[v] := ETIQ.0

    devuelve D{Q D = caminos_mnimos(g, v)}

    Fig. 6.27: el algoritmo de Dijkstra usando colas prioritarias.

    3 4 4 Estructuras de datos. Especificacin, diseo e implementacin __________________________________________________________________________________

  • La eficiencia temporal se puede mejorar an ms si estudiamos el funcionamiento delmontculo. Destaquemos que el algoritmo efecta exactamente n-1 hundimientos deelementos y, por otro lado, hasta un mximo de a flotamientos de manera que, en el casogeneral, hay ms flotamientos que hundimientos. Estudiando estos algoritmos (v. fig. 5.42),se puede observar que un hundimiento requiere un nmero de comparaciones quedepende tanto de la aridad del rbol como del nmero de niveles que tiene, mientras que unflotamiento depende tan slo del nmero de niveles: cuantos menos haya, ms rpido subirel elemento hacia arriba. Por tanto, puede organizarse el montculo en un rbol k-ario y nobinario, de manera que la altura del rbol se reduce. En [BrB87, pp. 93-94] se concluye que,con esta estrategia, el coste del algoritmo queda, para grafos densos, (n 2) y, para otrostipos, se mantiene (a logn), de manera que la versin resultante es la mejor para cualquiergrafo representado por listas de adyacencia, independientemente de su nmero de aristas16.

    Notemos que las diferentes versiones del algoritmo de Dijkstra presentadas aqu nodevuelven la secuencia de nodos que forman el camino mnimo. La modificacin es sencilla yqueda como ejercicio para el lector: notemos que, si el camino mnimo entre v y w pasa porun vrtice intermedio u, el camino mnimo entre v y u es un prefijo del camino mnimo entrev y w, de manera que basta con devolver un vector C, tal que C[w] contenga el nodo anterioren el camino mnimo de v a w (que ser v si est directamente unido al nodo de partida, o sino hay camino entre v y w). Este vector tendr que ser actualizado al encontrarse un atajo enel camino (en realidad, el vector representa un rbol de expansin -v. seccin 6.5- conapuntadores al padre, donde v es la raz). Es necesario tambin disear una nueva accinpara recuperar el camino a un nodo dado, que tendra como parmetro C.

    6.4.2 Camino ms corto entre todo par de nodos

    Se trata ahora de determinar el coste del camino ms corto entre todo par de vrtices de ungrafo etiquetado (ing., all-pairs shortest paths); de esta manera, se puede generalizar lasituacin estudiada en el apartado anterior, y queda plenamente justificada su utilidad. Unaprimera solucin consiste en usar repetidamente el algoritmo de Dijkstra variando el nodoinicial; ahora bien, tambin se dispone del llamado algoritmo de Floyd, que proporciona unasolucin ms compacta y elegante pensada especialmente para esta situacin. El algoritmode Floyd, definido por R.W. Floyd en 1962 sobre grafos dirigidos (su extensin al caso nodirigido es inmediata y queda como ejercicio para el lector) en "Algorithm 97: Shortest path",Communications ACM , 5(6), p. 345, es un algoritmo dinmico17 que se estructura como un

    Relaciones binarias y grafos 3 4 5__________________________________________________________________________________

    16 Hay implementaciones asintticamente ms rpidas que usan una variante de montculo llamadamontculo de Fibonacci (ing., Fibonacci heap), introducida por M. Fredman y R. Tarjan en 1987, que porsu complejidad no se explica en este texto; v., por ejemplo, [HoS94, pp. 488-494].17 La programacin dinmica (ing., dynamic programming) es una tcnica que estructura los algoritmoscomo bucles que, en cada paso, se acercan ms a la solucin, pero sin asegurar la obtencin deninguna parte definitiva antes de la finalizacin del algoritmo; para ms detalles consultar, por ejemplo,[BrB87].

  • bucle, que trata un vrtice denominado pivote en cada iteracin, y que usa un vectorbidimensional D indexado por pares de vrtices para guardar la distancia mnima. Cuando ues el pivote, se cumple que D[v, w] es la longitud del camino ms corto entre v y w formadontegramente por pivotes de pasos anteriores (excluyendo posiblemente las extremidades).La actualizacin de D consiste en comprobar, para todo par de nodos v y w, si la distanciaentre ellos se puede reducir pasando por el pivote u mediante el clculo de la frmulaD[v, w ] = min(D[v, w], D[v, u ] + D[u, w]). As pues, hay un par de diferencias en elfuncionamiento de este algoritmo y el de Dijkstra: por un lado, los vrtices se tratan en unorden independiente de las distancias y, por el otro, no se puede asegurar que ningunadistancia mnima sea definitiva hasta que acaba el algoritmo. Debe notarse que el algoritmofunciona incluso con aristas negativas, siempre que no haya ciclos negativos (es decir, que lasuma de las etiquetas de las aristas que los componen no sea negativa), motivo por el que sepodra relajar la restriccin de aristas no negativas.

    0 5

    2

    8 0

    7 0

    2

    (a) estado inicial (b) pivote = 1

    1

    3

    85

    2

    2

    (c) pivote = 2 (d) pivote = 3

    28

    0 5

    2

    8 0

    8 0

    2

    0 5

    2

    4 0

    7 0

    2

    0 5

    2

    8 0

    7 0

    2

    7 7

    Fig. 6.28: ejemplo de funcionamiento del algoritmo de Floyd.

    La especificacin del problema se propone en el ejercicio 6.32; los comentarios son losmismos que en la especificacin del algoritmo de Dijkstra. La implementacin se presenta enla fig. 6.29. Notemos que la diagonal de D se inicializa a cero y nunca cambia. Por otra parte,observemos que tanto la fila como la columna del vrtice u tratado en un paso del algoritmopermanecen invariables en este paso, por lo que se puede trabajar con una nica matriz paraactualizar las distancias mnimas. La inicializacin de la matriz es ineficiente en caso de que elgrafo est implementado por (multi)listas de adyacencia, pero se deja as porque no afecta alcoste total del algoritmo; si se considera conveniente, se puede modificar de manera similaral algoritmo de Dijkstra de la fig. 6.27, sustituyendo las n2 llamadas a etiqueta por n buclessobre los sucesores, de coste total a. El invariante usa una funcin pivotes(u), que devuelve

    3 4 6 Estructuras de datos. Especificacin, diseo e implementacin __________________________________________________________________________________

  • el conjunto de vrtices que han sido pivotes en pasos anteriores del algoritmo, lo que sepuede determinar a partir del pivote del paso actual dado que los vrtices son un tipo escalar(si no, el invariante necesitara mantener un conjunto de los vrtices que han sido pivotes).

    {P g es un grafo dirigido etiquetado que no contiene ciclos negativos}funcin Floyd (g es grafo) devuelve vector [vrtice,vrtice] de etiq esvar D es vector [vrtice, vrtice] de etiq; u, v, w son vrtice fvar

    {inicialmente la distancia entre dos vrtices tiene el valor de la arista quelos une; las diagonales se ponen a cero}

    para todo v dentro de vrtice hacerpara todo w dentro de vrtice hacer

    D[v, w] := etiqueta(g, v, w) { si no hay arco}fpara todoD[v, v] := ETIQUETA.0

    fpara todopara todo u dentro de vrtice hacer

    {I v: vvrtice: w: wvrtice:D[v, w] = mnimo({coste(C) / Ccaminos(g, v, w)

    C(pivotes(u){v, w}) = C})para todo v dentro de vrtice hacer

    para todo w dentro de vrtice hacersi D[v, u]+D[u, w] < D[v, w] entonces D[v, w]:= D[v, u] + D[u, w] fsi

    fpara todofpara todo

    fpara tododevuelve D{Q D = todos_caminos_mnimos(g, v)} -- v. ejercicio 6.32

    Fig. 6.29: una codificacin del algoritmo de Floyd.

    La eficiencia temporal del algoritmo de Floyd es (n3), independientemente de larepresentacin, igual que la aplicacin reiterada de Dijkstra trabajando con unarepresentacin del grafo mediante matriz de adyacencia. Ahora bien, es previsible que Floydsea ms rpido (dentro del mismo rden asinttic