You are on page 1of 76

Tipos abstractos

de datos
Especificacin e implementacin
Xavier Franch Gutirrez
Fatos Xhafa
P01/75001/00075
FUOC P01/75001/00075 Tipos abstractos de datos
ndice
Introduccin............................................................................................... 5
Objetivos...................................................................................................... 8
1. Breve resumen de la programacin orientada a objetos........... 9
2. Una jerarqua de TAD......................................................................... 11
2.1. Los contenedores............................................................................... 12
2.1.1. Concepto de contenedor ....................................................... 12
2.1.2. Contenedores recorribles....................................................... 14
2.1.3. Contenedores acotados.......................................................... 14
2.1.4. La jerarqua de elementos...................................................... 15
2.1.5. Conclusin............................................................................. 16
2.2. Una primera clasificacin de los contenedores................................. 17
2.2.1. Las secuencias......................................................................... 19
2.2.2. Los rboles binarios................................................................ 20
2.2.3. Los conjuntos......................................................................... 22
2.2.4. Las funciones.......................................................................... 22
2.2.5. Las relaciones......................................................................... 23
2.3. Traduccin de la jerarqua a Java...................................................... 26
2.3.1. Simulacin de la genericidad................................................. 27
2.3.2. Simulacin de la herencia mltiple....................................... 27
2.3.3. Otras cuestiones..................................................................... 29
3. Implementacin de TAD.................................................................... 30
3.1. Representacin del TAD .................................................................... 31
3.1.1. Los atributos del TAD............................................................. 31
3.1.2. El invariante de la representacin.......................................... 31
3.2. Codificacin de las operaciones........................................................ 32
3.3. Escritura de implementaciones en Java............................................. 33
4. Eficiencia de las implementaciones................................................ 35
4.1. Eficiencia temporal ............................................................................ 38
4.2. Eficiencia espacial .............................................................................. 42
5. Representacin de contenedores usando vectores....................... 44
5.1. Representacin secuencial ................................................................. 44
5.1.1. Presentacin........................................................................... 44
5.1.2. Una primera representacin secuencial ................................. 46
5.1.3. Una segunda representacin secuencial ................................ 48
5.1.4. Representaciones secuenciales marcadas............................... 49
5.1.5. Representaciones secuenciales ordenadas.............................. 51
5.2. Representaciones encadenadas.......................................................... 53
5.2.1. Algunas variantes de representaciones encadenadas............. 57
5.3. Tabla comparativa de las implementaciones vistas.......................... 58
6. Implementacin de TAD con una memoria dinmica............... 59
6.1. La memoria dinmica en Pascal ........................................................ 60
6.2. La memoria dinmica en Java........................................................... 62
6.3. La asignacin y la igualdad ............................................................... 63
6.4. Riesgos del uso de la memoria dinmica........................................... 65
Resumen....................................................................................................... 67
Actividades.................................................................................................. 69
Ejercicios de autoevaluacin.................................................................. 69
Solucionario................................................................................................ 71
Glosario........................................................................................................ 74
Bibliografa................................................................................................. 75
FUOC P01/75001/00075 Tipos abstractos de datos
FUOC P01/75001/00075 5 Tipos abstractos de datos
Introduccin
En este mdulo presentamos el concepto de tipo abstracto de datos (TAD),
que acta como un eje vertebrador de los contenidos de la asignatura. Hace-
mos una breve presentacin del concepto, detallamos qu TAD se desarrollan
durante la asignatura y nos centramos en la nocin de implementacin de los
TAD, mostrando las estrategias ms habituales para construirlos. Como parte
de este ltimo punto, presentamos el mecanismo de memoria directa presente
en todos los lenguajes de programacin modernos, y en particular, en los len-
guajes orientados a objetos.
Un tipo abstracto de datos se define como un dominio de valores sobre los que
se pueden aplicar una o ms operaciones, que tambin forman parte del TAD.
El concepto de TAD es la evolucin natural de la nocin ms primitiva detipos
de datos, propia de los programas de los aos sesenta, que se centraban en los
valores y obviaban las operaciones.
Trabajando con TAD, los nuevos tipos de datos se manipulan mediante unas
operaciones que se introducen al mismo tiempo (de hecho, las operaciones se de-
finen antes de escribir la representacin del tipo), y de esta manera se evita la dis-
persin del cdigo que involucra un TAD. Si, adems, la definicin del TAD se
encapsula en un mdulo compilable de forma separada, se obtiene un producto
final claramente estructurado, fcilmente analizable, robusto, mantenible.
El concepto de TAD ya se present en la asignatura Fundamentos de programa-
cin II, en la que se destacaba la similitud que presenta con respecto a la nocin
de clase en la orientacin a objetos, de la que en realidad es predecesora.
En esta asignatura consideramos que una clase es el mecanismo de encapsula-
miento de un TAD (es decir, la construccin sintctica que lo contiene), dado
que una clase tambin se puede usar con otros significados.
Un TAD consta de dos partes:
1) Laespecificacin. Introduce las operaciones de TAD (nombre e interfaz) y
fija su comportamiento*. El comportamiento se puede determinar de diferen-
tes maneras: mediante comentarios informales, mezclando explicaciones in-
formales y formales, o mediante especificaciones totalmente formales. En esta
asignatura explicaremos el comportamiento de cada operacin de una forma
informal y, a la vez, daremos una especificacin ms precisa, basada en el mo-
delo matemtico del TAD.
2) La implementacin. Determina una representacin de los valores del
TAD y la codificacin de las operaciones de acuerdo con esta representacin.
Abreviamos la expresin tipo
abstracto de datoscon la sigla TAD.
Otros significados
de las clases
La clase System.out de Java
no es un TAD, sino slo una
coleccin de mtodos interre-
lacionados.
* Por ejemplo, podemos tener
un TAD conjunto con operaciones
de conjunto vaco, aadir
elemento, etc.
FUOC P01/75001/00075 6 Tipos abstractos de datos
Larepresentacin consistir en elegir una estructura de datos adecuados para la
especificacin dada y un predicado de correccin*. Veremos que es importante
la eleccin de una representacin adecuada de valores, dados los requisitos del
TAD, principalmente por lo que se refiere a la eficacia en tiempo y en espacio.
Desde el momento en que queremos estudiar los TAD dentro del marco de la
orientacin a objetos, es conveniente organizarlos segn una jerarqua de cla-
ses adecuada. La jerarqua de tipos abstractos de datos est diseada no slo
para incorporar todos los TAD aqu vistos, sino para poder extenderla a otros
TAD que, por motivos de carga docente, no se presentan en la asignatura.
Para construir esta jerarqua usaremos todos los conceptos de la orientacin a
objetos vistos en la asignatura Fundamentos de programacin II, que se repasan
brevemente en la primera seccin de este mdulo. Veremos que la herencia
nos ayuda a definir los TAD por especializacin, de forma que un TAD se ob-
tiene despus de un proceso de refinamiento.
La raz modeliza el concepto general de contenedor de datos; puede ser de
cinco tipos principales: secuencias, rboles binarios, conjuntos, funciones y
relaciones. Cada uno de stos se refina a su vez en otros, ms concretos, que
forman los TAD (que se estudian individualmente en otros mdulos de la asig-
natura). Hay que mencionar que, a partir del concepto bsico de contenedor,
se definen diferentes especializaciones que presentan algunas variantes habi-
tuales de esta nocin. El resultado es la existencia (por lo menos conceptual)
de distintas jerarquas paralelas.
La jerarqua se desarrolla sin pensar en las restricciones que un lenguaje orien-
tado a objetos particulares puede imponer sobre los mecanismos utilizados.
Ahora bien, dado que seguiremos usando Java como un lenguaje de trabajo de
la asignatura, estudiamos tambin cmo hay que adaptar la jerarqua a las par-
ticularidades de este lenguaje, especialmente por lo que se refiere a la ausencia
de genericidad y de herencia mltiple entre clases.
El resto de los mdulos se dedica al estudio de cuestiones relacionadas con la
implementacin de los TAD. Primero, se enumeran y se estudian las distintas
partes que forman una implementacin, como ya hemos mencionado. Tam-
bin aqu se opta por utilizar una notacin algortmica, similar a la que ya co-
nocis, y entonces se nombran las restricciones y particularidades de Java.
A continuacin, nos enfrentaremos al problema de medir las implementaciones
construidas. Tomamos la eficiencia como un criterio de medida, es decir, el
tiempo de ejecucin de las operaciones que se tienen que llevar a cabo, el espa-
cio necesario para representar el tipo y, eventualmente, el espacio adicional que
necesitan las operaciones cuando se ejecutan. Discutiremos la unidad de medi-
da de la eficiencia y detallaremos las reglas bsicas que permiten calcularla a par-
tir de los constructores de tipo e instrucciones que forman la implementacin.
* Por ejemplo, podemos
implementar un conjunto
con vectores, con memoria
dinmica, etc.
Un contenedor es un almacn
de datos de cualquier tipo.
Consultad los TAD individuales
estudiados en los mdulos
Secuencias y rboles, Funciones
y conjuntos y Relaciones de esta
asignatura.
Consultad la notacin algortmica
utilizada en la asignatura
Fundamentos de programacin I.
Necesidad de medir
las implementaciones
Es necesario medir las implemen-
taciones no slo para conocer
con detalle las caractersticas,
sino tambin para elegir la ms
adecuada cuando un TAD tiene
ms de una.
FUOC P01/75001/00075 7 Tipos abstractos de datos
Por ltimo, introduciremos las estrategias generales de representacin de TAD
que usaremos a lo largo del curso, clasificadas en dos familias:
a) Lasestrategias secuenciales se caracterizan por el hecho de que la estructura
de datos que aparece en la representacin (tpicamente, un vector) se divide
conceptualmente en dos partes, la parte libre y la parte ocupada, que contiene
todos los elementos consecutivos segn un criterio determinado*. Veremos va-
rias variantes de estas estrategias.
b) Por lo que se refiere a las estrategias encadenadas, introduciremos el con-
cepto general que se basa en romper esta continuidad de los elementos, y des-
pus nos centraremos en su implementacin usando la memoria dinmica del
ordenador.
Estas estrategias generales se adaptarn a los TAD concretos, o se complemen-
tarn con tcnicas ms especficas.
La memoria dinmica es un espacio de datos que se adapta al crecimiento y
decrecimiento de las estructuras de datos que implementan los TAD. A diferen-
cia de los vectores, el espacio de la estructura no est predeterminado. Cuando
se inserta un elemento, el cdigo de la operacin reclama el espacio necesario
para almacenarlo, y cuando se destruye, el espacio se libera (en algunos lengua-
jes de forma implcita, en otros explcitamente). Estudiaremos tanto los efectos
positivos como los negativos del uso de memoria dinmica, en comparacin
con los vectores.
* Tpicamente, orden de entrada
en el contenedor u ordenacin
segn un campo (entero o cadena
de caracteres, normalmente).
FUOC P01/75001/00075 8 Tipos abstractos de datos
Objetivos
Los materiales asociados a este mdulo didctico permitirn al estudiante al-
canzar los siguientes objetivos:
1. Asimilar el concepto de tipo abstracto de datos (TAD) y su relacin con los
conceptos propios de la orientacin a objetos.
2. Entender los principios bsicos de la programacin por diferencias median-
te el estudio de la jerarqua de TAD de la asignatura.
3. Obtener una primera panormica de todos los TAD que se estudiarn du-
rante la asignatura y entender las diferencias esenciales que presentan.
4. Conocer las partes que componen una implementacin de TAD.
5. Entender el significado de la notacin asinttica O-grande como criterio
para medir la eficiencia y ser capaces de aplicar su definicin en el clculo
de la eficiencia de las implementaciones de TAD y algoritmos que veremos
a lo largo de la asignatura.
6. Disponer de un marco de trabajo para la definicin de representaciones
particulares de TAD.
7. Conocer el concepto de memoria dinmica y su funcionamiento concreto
en dos lenguajes de programacin diferentes.
8. Profundizar en el conocimiento del lenguaje de programacin Java, espe-
cialmente en lo concerniente a la definicin de jerarquas y a la implemen-
tacin de TAD.
FUOC P01/75001/00075 9 Tipos abstractos de datos
1. Breve resumen de la programacin orientada
a objetos
En otra asignatura se ha definido la orientacin a objetos como un paradigma
de programacin basado en la encapsulacin y la ocultacin de la informa-
cin, la abstraccin y la clasificacin, y el polimorfismo y la herencia.
Algunas clases no permiten crear instancias. Los motivos pueden ser dos (no
exclusivos): que existe algn mtodo sin implementar, o bien que la clase ca-
racteriza ciertas propiedades del dominio. En el primer caso hablamos de cla-
ses diferidas (y mtodos diferidos), y en el segundo, de clases abstractas.
Tambin conviene recordar la existencia de clases genricas (clases parame-
trizadas), en las que el tipo de determinantes atribuidos est sin concretar. Su
utilidad es enorme, porque permiten definir categoras similares de clases de
una sola vez.
En esta asignatura, y dadas la definicin de clase y las caractersticas menciona-
das, usamos las clases como un mecanismo de encapsulacin de los TAD.
En este contexto, aadimos algunas clasificaciones adicionales de las clases.
Primero, distinguimos las clases de especificacin y las clases de implemen-
tacin. Las primeras encapsulan especificaciones de TAD y tomarn la forma
de clases diferidas sin ningn mtodo implementado. Las segundas encapsu-
lan las implementaciones y tendrn todos los mtodos implementados.
Los atributos y mtodos de las clases tienen asociado un mbito, que indica el
grado de acceso que tienen sobre este elemento las diferentes clases que con-
figuran el programa. Los mbitos pueden ser de tres tipos: privado (local de
la clase), protegido (permite el acceso a los herederos de la clase) y pblico
(acceso libre). La definicin correcta de los mbitos es primordial para asegurar
la buena programacin y para respetar el principio de ocultacin de la infor-
macin (que controla el acceso a los recursos de la clase).
Laclase es la unidad bsica de encapsulacin, que combina estructural-
mente un conjunto de datos (representados por atributos) y un conjun-
to de operaciones (o mtodos).
Losobjetos que interaccionan en los programas construidos con lengua-
jes orientados a objetos son instancias de clases: slo pueden tomar los
valores permitidos por la clase, y slo se les puede aplicar mtodos de cla-
se. Los objetos se crean mediante los llamados mtodos constructores,
y se destruyen tambin mediante mtodos o bien de forma implcita.
Consultad la definicin de orientacin
a objetosen la asignatura
Fundamentos de programacin II.
Consultad los conceptos de
especificacin e implementacin de
un TAD en la introduccin de este
mdulo didctico.
En Java
las clases de especificacin
tomarn la forma de interfaces
en lugar de clases.
FUOC P01/75001/00075 10 Tipos abstractos de datos
Las clases se conectan segn varias formas de relacin. La herencia es la rela-
cin ms caracterstica: cuando una clase A hereda de una clase B, todos los
atributos y mtodos no privados de B lo son tambin de A. Adems, A puede
redefinir mtodos y aadir otros nuevos. La herencia favorece la llamada pro-
gramacin por diferencias, que enfatiza la identificacin de las diferencias que
existen entre las clases.
Conviene tener presentes algunos casos particulares de herencia. Primero, la he-
rencia mltiple, en la que una clase hereda ms de una. Es necesario determi-
nar qu pasa con los mtodos que se heredan ms de una vez. Un caso particular
de herencia mltiple es la herencia repetida, en la que una clase hereda de otra
ms de una vez*.
Si consideramos todas las clases relacionadas por herencia, podemos formar
jerarquas de clase, que denotan todas las interrelaciones existentes. Las jerar-
quas de clases conforman una representacin estructurada de los dominios
del conocimiento.
El polimorfismo es una caracterstica ineludiblemente asociada a la herencia
y se refiere a las distintas formas que puede tomar un objeto dependiendo de
cmo se construye. Cuando se ejecuta el programa, un objeto declarado de una
claseA puede crearse mediante una operacin constructora de una clase here-
dera de A. Entonces los mtodos aplicados al objeto en realidad se determinan
en tiempo de ejecucin, cuando realmente se sabe la forma que ha tomado el
objeto; es lo que se denomina vinculacin dinmica.
Al menos hemos recuperado el vocabulario orientado a objetos. Si hay algo
que no os queda claro, repasad los apuntes de Fundamentos de programacin II;
todo lo dicho aqu aparece en este material. Ahora ya podemos empezar con
la asignatura.
* Diferentes lenguajes presentan
varios tratamientos de esta
situacin.
FUOC P01/75001/00075 11 Tipos abstractos de datos
2. Una jerarqua de TAD
Los mecanismos de la orientacin a objetos que hemos visto nos permiten es-
tructurar los programas en clases interrelacionadas, as como formar libreras
temticas de TAD reutilizables encapsuladas en clases. Este segundo punto es
precisamente el que aqu nos interesa.
El objetivo de este apartado es ofrecer un catlogo verstil de TAD, encapsula-
dos en clases genricas y organizados jerrquicamente, para poder gestionar co-
lecciones de elementos segn diferentes polticas de acceso. En esta jerarqua
usamos varios criterios de clasificacin, que permiten comprender las diferen-
cias entre los TAD disponibles. Durante el desarrollo utilizaremos la herencia
para representar especialmente una relacin: la especializacin. De esta forma,
cuando los programas necesiten almacenar conjuntos de elementos, podrn
reutilizar los TAD de esta librera, idealmente sin ninguna modificacin, o bien
creando un nuevo TAD encapsulado en una nueva clase, como una especiali-
zacin de uno o varios TAD ya existentes.
Hay que indicar que no incluimos las clases de implementacin en la jerarqua,
de forma que stas son, pues, clases diferidas que podrn ser abstractas o no.
Empezaremos por introducir el concepto de contenedor como nexo de todos los
TAD que forman parte de una jerarqua, y veremos distintas variantes de este
concepto. Despus daremos una primera clasificacin de los TAD resultantes en
cinco tipos principales. Estudiaremos estas cinco clases, comentaremos unos
cuantos aspectos interesantes y entenderemos la aparicin de ciertos criterios
recurrentes. El estudio detallado se expone en los mdulos Secuencias y rbo-
les, Funciones y conjuntos y Relaciones de esta asignatura.
Antes de empezar, expresaremos unos breves comentarios:
1) En las clases slo se incluyen las operaciones indispensables para caracteri-
zar los TAD definidos.
2) La jerarqua se mantiene dentro de unos lmites manejables dada la carga
docente de la asignatura.
3) Por motivos de espacio, y tambin para no caer en la monotona, la jerar-
qua no se presenta de forma completa.
4) Los TAD aparecen en los otros mdulos de la asignatura de forma indivi-
dual. En este mdulo ofrecemos una panormica general que nos ayudar a
comprender la misin de cada tipo, y ms adelante, tendremos una descrip-
cin ms individualizada que resumir las caractersticas que poco a poco se
van aadiendo, principalmente mediante la herencia.
Recordad que el concepto de
librera de clases se ha introducido
en la asignatura Fundamentos
de programacin II.
Recordad que la utilidad de la
orientacin a objetos en el contexto
de la reutilizacin de softwarese ha
estudiado en la asignatura Fundamentos
de programacin II.
Podis obtener una panormica
general de la jerarqua Contenedor
en el material del aula
de esta asignatura.
Como se indica en la actividad 1, hay
otros TAD, as como ampliaciones y
variantes de los TAD estudiados, cuya
existencia aumentara la versatilidad
de la librera.
Podis ver la actividad 2
de este mdulo didctico.
FUOC P01/75001/00075 12 Tipos abstractos de datos
2.1. Los contenedores
Aqu definiremos el concepto de contenedor y describiremos los principales
tipos de contenedores existentes.
2.1.1. Concepto de contenedor
El concepto de contenedor es muy general; lo representamos mediante una
clase diferida parametrizada:
diferida, porque algunos mtodos no se pueden implementar;
parametrizada, porque el comportamiento del TAD es independiente de los ti-
pos de elementos almacenados. El parmetro es la clase de elementos que se de-
ben almacenar, sin ningn requisito adicional, excepto que se pide la existencia
de una funcin que permita adivinar si dos elementos son iguales. Hay algunos
tipos particulares de contenedores que s formulan alguna restriccin adicional
sobre los elementos (por ejemplo, que formen un dominio ordenado), pero esta
clase de requisitos tendr que aparecer localmente all donde haga falta.
En general, cualquier contenedor estar caracterizado por tres tipos de operacio-
nes: insercin, supresin y algn tipo de consulta sobre elementos individuales.
La forma que tomarn estas operaciones puede ser muy diferente dependiendo
del tipo de contenedor.
Ejemplos de operacin de insercin en un contenedor
Consideremos la operacin de insercin. Si bien la mayora de los contenedores inserta
un valor en un solo contenedor, hay TAD en los que el valor consta de dos componentes
(por ejemplo, un contenedor que relacione a personas y empresas) que dan lugar a dos
parmetros diferentes en la interfaz de la operacin. En otros, se exige la existencia de
una clave que identifique los elementos (por ejemplo, contenedores de personas identi-
ficadas por el DNI). Tambin pueden existir varias operaciones de insercin (por ejemplo,
insercin en el inicio e insercin en el final en contenedores ordenados). Por este motivo,
en la definicin ms abstracta de los contenedores no puede haber una sola forma comn
con la operacin de insercin.
As pues, cules son los servicios que debe definir la clase Contenedor conce-
bida como la raz de la jerarqua de clases? En general, lo nico que podemos
decir de los contenedores es lo siguiente:
1) Debe ser posible crearlos y destruirlos; por este motivo tendremos una ope-
racin para crear el contenedor vaco y otra para destruir el contenedor creado.
2) Todo contenedor tendr una ocupacin determinada; por eso definimos un
atributo, tamao, que registra el nmero de elementos que estn contenidos. Se
define como atributo protegido (as, todos los TAD de la jerarqua podrn ac-
ceder a ste, pero no sus usuarios) y, en consecuencia, hay que definir un nuevo
Denominaremoscontenedor cualquier TAD que se caracterice por con-
tener un conjunto de elementos.
En el anexo de este mdulo
encontraris la implementacin en
Java de algunos contenedores de los
que se presentan.
Ejemplos de contenedores
Un TAD para registrar a los so-
cios de un club; un TAD para
guardar las direcciones web de
una hiperagenda; un TAD para
guardar un conjunto de iconos,
etc. Todos estos TAD son casos
particulares de contenedores.
Otras operaciones
de los contenedores
Adems de las operaciones
bsicas, los contenedores
ofrecern otras: creacin,
destruccin, predicados,
recorridos, y otras ms
especficas.
Atributos protegidos
Recordad que un atributo
protegido es aquel sobre el cual
slo se tiene acceso en la clase
que lo define y en sus herederas.
FUOC P01/75001/00075 13 Tipos abstractos de datos
mtodo que devuelva su valor. Dada su utilidad, definimos an otro mtodo
que indica si el contenedor est vaco o no. Observad que estas dos operaciones
pueden implementarse completamente en funcin del atributo tamao.
3) Sus elementos son todos del mismo tipo (que acta como un parmetro de
la clase), sobre el cual no se pide ms que una funcin para saber si dos ele-
mentos son iguales.
En la figura siguiente se ofrece la representacin en UML de la claseContenedor
y de varias clases herederas que estudiamos en este mdulo. Para anotar expl-
citamente el tipo de parmetro del TAD, usamos la facilidad de UML para aa-
dir nuevos compartimentos en las cajas que representan las clases. UML ofrece
construcciones que permitiran definir los parmetros de forma ms elegante.
Pese a todo, rechazamos su uso para no complicar el temario excesivamente,
y porque la solucin que adoptamos cubre nuestras necesidades.
FUOC P01/75001/00075 14 Tipos abstractos de datos
2.1.2. Contenedores recorribles
Aparte de las operaciones de acceso individual antes mencionadas, otra fun-
cin que pediremos a menudo a los contenedores es la obtencin de todos sus
elementos, a veces siguiendo un orden determinado, a veces en orden aleato-
rio. Estos contenedores los denominaremos contenedores recorribles.
Como paso previo a la definicin de los contenedores recorribles, formulamos
la clase Iterador, que ofrece las cuatro opciones mencionadas. Entonces, los con-
tenedores recorribles se pueden definir simplemente por herencia mltiple de
las clases Contenedor e Iterador.
Fijmonos en que la clase Iterador no establece ningn orden de visita de los
elementos almacenados en el contenedor. Este orden es aleatorio y depende
de factores, en principio, no controlables por el programador (por ejemplo, el
orden de insercin y las estrategias de implementacin del tipo). Sin embargo,
en varios TAD interesa imponer un orden en el recorrido.
Por este motivo definimos la clase heredera deIterador, IteradorOrdenado, que re-
quiere que los elementos sean comparables mediante alguna operacin (es de-
cir, que formen un dominio totalmente ordenado). El efecto de esta restriccin
aparece en el tipo de los elementos, que deja de ser Elem y pasa a ser ElemOrd.
La correspondiente restriccin de orden que aparece en ElemOrd establece las
propiedades de ordenacin que caracterizan este recorrido.
La definicin de los contenedores recorribles ordenadamente es similar a Con-
tenedorRecorrible.
2.1.3. Contenedores acotados
Los TAD contenedores definidos hasta ahora tienen una capacidad infinita: se
puede ir insertando un elemento tras otro sin ningn tipo de restriccin. Esta
situacin no se produce nunca por motivos de implementacin. Muchas veces
usamos vectores para representar los tipos, y entonces tenemos que controlar
que la estructura no se llene por encima de su capacidad. As pues, la imple-
mentacin por vectores no se ajusta a la implementacin dada.
Por eso, si queremos obtener una jerarqua adecuada, debemos tener en cuen-
ta este hecho.
En todos los casos, los contenedores recorribles seguirn el mismo pa-
trn: se situarn sobre el primer elemento, y despus consultarn el ele-
mento actual y avanzarn al siguiente reiteradamente, hasta llegar al final.
El patrn de los contenedores
recorribles es idntico al clsico
recorrido de secuencias que conocis
de la asignatura Fundamentos de
programacin I.
Ejemplo de orden
en el recorrido
Un ejemplo tpico en el que hay
que imponer un orden en el re-
corrido sera el caso en que los
elementos son cadenas de
caracteres, y estas cadenas se
quieren obtener en orden
alfabtico.
Consultad la definicin de ElemOrd
en el subapartado 2.1.4. de este
mdulo didctico.
Causas del agotamiento
del espacio
Una situacin que puede pro-
ducir agotamiento del espacio
se da cuando slo utilizamos
memoria dinmica (introduci-
da en el apartado 6), que va
asignando espacio a medida
que las implementaciones la
necesitan, porque en realidad
la memoria del ordenador no
es infinita.
FUOC P01/75001/00075 15 Tipos abstractos de datos
En la nueva clase, existen varias formas de representar la dimensin mxima
de un TAD acotado:
Se puede aadir a la clase un parmetro formal en la clase que la represente.
Se puede introducir un atributo de clase.
Se puede pasar la dimensin como parmetro de la operacin de creacin.
Optamos aqu por la tercera opcin, a causa de la flexibilidad que nos propor-
ciona: varios objetos de una misma clase se pueden crear con una capacidad
diferente. Tambin influye en la eleccin la facilidad de implementar este es-
quema mediante Java.
En la clase resultante destaca la redefinicin de la operacin de creacin, as
como la aparicin de una nueva operacin para saber si el contenedor est
lleno.
A partir de aqu, combinando con los dos tipos de iterador que hemos visto,
podemos crear dos contenedores recorribles acotados.
2.1.4. La jerarqua de elementos
Como hemos avanzado, a lo largo del apartado se formularn varias restricciones
sobre los elementos que se almacenan en los contenedores. Para estructurar estos
elementos, hemos optado por relacionarlos con la jerarqua UML de la siguiente
figura; pese a que somos conscientes de que los lenguajes orientados a objetos
ms habituales no soportan la definicin de jerarquas sobre los parmetros.
La raz del diagrama es la clase de los elementos sin ninguna otra operacin
que la igualdad. A partir de esta operacin, se definen varias especializaciones:
a) A la clase ElemOrd le aadimos una operacin de orden total, especialmen-
te til en el caso ya visto de los iteradores ordenados.
b) La clase ElemEsp simplemente identifica un elemento especial dentro del
dominio, que puede servir de indicador en diferentes situaciones*.
c) Para cerrar este primer nivel, la clase ElemClave define los elementos en los
que se puede distinguir una clave que los identifica; la funcin f es la que per-
mite obtener la clave del elemento*.
La clase ContenedorAcotado, heredera de contenedor, se introduce para
controlar que no se produzca un desbordamiento en esta familia de TAD.
* Por ejemplo, una persona
sin DNI identifica un caso especial
de persona.
* Por ejemplo, el DNI
de una persona.
FUOC P01/75001/00075 16 Tipos abstractos de datos
En un segundo nivel, por herencia mltiple de estas nuevas clases, obtenemos
tres ms:
a) Primero, la clase ElemOrdClave, que permite comparar las claves de los ele-
mentos de ElemClave.
b) Tambin, ElemClaveEsp, en el que la clave tiene un valor especial, que uti-
lizaremos sobre todo como un indicador de inexistencia de un elemento en
un contenedor.
c) Por ltimo, ElemSum, que hereda de ElemOrd y ElemEsp y, adems, aade
una operacin de suma de los elementos, as como un segundo elemento es-
pecial; esta clase nos permitir asignar pesos a los elementos.
Finalmente, definimos una clase llamada ElemClaveEspOrd, de comportamien-
to combinado segn las clases de las que hereda.
2.1.5. Conclusin
Del estudio de este apartado se puede llegar a la conclusin de que el concep-
to de contenedor es el eje vertebrador del estudio de los TAD que llevaremos
a cabo en esta asignatura, as como de que la nocin bsica se puede adaptar
FUOC P01/75001/00075 17 Tipos abstractos de datos
segn algunos criterios que se han visto aqu (capacidad acotada y recorrido)
y otros que no se mencionan (por ejemplo, contenedores persistentes o no).
Un efecto de esta variedad de contenedores es el siguiente: la mayora de los
TAD que veremos se puede definir en realidad segn todas estas variedades. Por
eso, se puede imaginar que hay, ms que una nica jerarqua de TAD, varias je-
rarquas paralelas que slo cambian en la raz (la clase concreta de contenedor).
Est claro que esta diferencia resulta fundamental, dado que todas las clases de
una de estas jerarquas heredan los atributos, mtodos y restricciones propios de
su raz correspondiente.
En la mayor parte de la asignatura nos centraremos en la jerarqua que de-
pende de la clase bsica Contenedor, si bien en algunos puntos nos referire-
mos al resto de las jerarquas, tanto por el hecho de que existen TAD que
carecen de sentido si no se pueden recorrer como por el hecho de tener ejem-
plos de diferentes tipos.
2.2. Una primera clasificacin de los contenedores
Dada su funcionalidad, distinguimos cinco clases principales de contenedo-
res, clases que presentamos a continuacin. Como no poda ser de otra forma,
todos provienen de la implantacin de conceptos matemticos clsicos.
Contenedor persistente
Entendemos por contenedor
persistente aquel que conserva
los datos entre diferentes eje-
cuciones de un programa.
FUOC P01/75001/00075 18 Tipos abstractos de datos
1) Las secuencias representan disposiciones lineales de elementos. Se carac-
terizan por la existencia de un primer elemento, un ltimo elemento y una po-
ltica de acceso a los elementos siguiendo este orden lineal. Por este motivo,
las supresiones y las consultas afectan a unos elementos determinados por el
contenido mismo de la estructura. Los elementos se aaden de uno en uno.
En este nivel de abstraccin, y a causa de la diversidad de secuencias que estu-
diaremos, no se puede establecer ninguna propiedad que se refiera a estas ope-
raciones que sea igual para todas, excepto los errores de borrar o consultar en
una secuencia vaca.
2) Los rboles binarios nos sirven para introducir relaciones jerrquicas en un
dominio de elementos. Cada elemento est por encima de dos ms, como mucho,
y est por debajo de un tercero (salvo un elemento especial, la raz del rbol, que
no est por debajo de ningn otro). Esta relacin se hace patente en la signatura
de la operacin insercin (enraiza), que involucra a dos rboles y no slo a uno.
La operacin de supresin es en realidad doble (hizq y hder) y no afecta a un
nico elemento, sino a varios. La consulta obtiene siempre el elemento ms
relevante de la jerarqua, es decir, la raz. La clase es diferida pero no abstracta,
dado que el comportamiento de las operaciones est completamente determi-
nado por las restricciones correspondientes.
3) Losconjuntos son la tercera clase de contenedor disponible. Hay una ope-
racin conmutativa para aadir elementos. La operacin de suprimir, por su
parte, no viene dada por la estructura misma como suceda en las dos catego-
ras anteriores, dada la ausencia de orden en la disposicin de los elementos
dentro del contenedor, sino que tenemos una operacin que explicita el ele-
mento que se debe suprimir. No se considera error suprimir un elemento que
no aparece, pese a que este punto es muy arbitrario. Finalmente, la operacin
de consulta se identifica con la pertenencia de los elementos a los conjuntos.
4) Las funciones son la cuarta familia de contenedores y se caracterizan por
la existencia de un segundo dominio de elementos. El contenedor se ocupa de
asociar un valor de este segundo dominio (alcance de la funcin) a todo ele-
mento del primero que aparezca (dominio de la funcin).
Por este motivo, la insercin implica pares de elementos, uno de cada dominio,
y se establecen dos propiedades que cualquier heredero de la clase debe cumplir:
La primera establece que la insercin de un par provoca que cualquier aso-
ciacin anterior para su primer elemento quede anulada.
La segunda afirma que, en cualquier caso, la insercin es conmutativa.
La supresin y la consulta se llevan a cabo de acuerdo con el primer elemento
del par insertado. La supresin y consulta de elementos que no estn en la fun-
cin es un error (la funcin es parcial), aunque algunas clases herederas rela-
jarn esta condicin.
FUOC P01/75001/00075 19 Tipos abstractos de datos
5) Por ltimo, hay una familia de contenedores que permite establecer relacio-
nes binarias entre pares de elementos. Al igual que suceda en las funciones, hay
dos dominios de elementos involucrados en el contenedor, y las operaciones de
aadir y borrar se refieren en este caso al establecimiento o ruptura de interrela-
ciones entre elementos de los dos dominios (si bien algunas especializaciones
tambin permitirn aadir y borrar elementos en los mismos dominios). La con-
sulta slo comprueba que se establecen interrelaciones entre un par de elementos.
Dada su necesidad en la prcticamente totalidad de algoritmos que involucran
relaciones binarias, existen operaciones para obtener todos los elementos de un
dominio relacionados con un elemento de otro. Dado que se trata de dos reco-
rridos posibles, conviene heredar dos veces de los iteradores, obtenindose dos
conjuntos de operaciones de recorrido (posiciona 1,...; posiciona 2,...). Es nece-
sario redefinir posiciona, pues aqu se necesita un parmetro de referencia.
Encontramos una especializacin particularmente relevante en el caso de que
los dos dominios sean el mismo. Hablamos entonces de grafos. En este caso,
a las operaciones habituales le aadimos otras muy especficas que provocan
diferentes algoritmos de inters.
En el resto de este subapartado desarrollaremos un poco ms los contenedores
que hemos presentado aqu. El estudio detallado de stos, especialmente por
lo que se refiere a las tcnicas de implementacin, es el ncleo de otros mdu-
los de la asignatura.
2.2.1. Las secuencias
Como ya hemos comentado, las secuencias distribuyen un dominio de elemen-
tos segn una relacin lineal. Es decir, todo elemento dentro de una secuencia
tiene un elemento anterior (excepto el primero) y un elemento posterior (excep-
to el ltimo). En algunas clases de secuencias, el anterior y el sucesor de un ele-
mento pueden cambiar a medida que la estructura evoluciona; en otras, no.
Podemos imaginar muchos TAD que responden a la descripcin de la secuen-
cia dada. Aqu nos limitaremos a introducir los cuatro ms habituales.
Para empezar, las pilas y las colas son los dos ms simples. En estos TAD las
operaciones slo afectan a los extremos de la secuencia. En la pila, se borra y
consulta el ltimo elemento insertado; en la cola, el primero que se insert.
Ejemplos de usos de pilas y colas
Las pilas se pueden utilizar para implementar funciones recursivas de forma eficiente; las
colas se utilizan para organizar los trabajos lanzados a una cola de impresin.
Una variante de las colas muy utilizada son las denominadas colas priorita-
rias, en las que la posicin que ocupa un elemento dentro de la cola viene
dada por su prioridad y no por el orden de insercin. Por eso, se formula un
Nomenclatura
Para distinguir, utilizamos el
trmino relacin para el TAD
e interrelacin para la relacin
establecida entre dos elemen-
tos de los dominios.
Consultad los mdulos Secuencias
y rboles, Funciones y conjuntos
y Relaciones de esta asignatura.
FUOC P01/75001/00075 20 Tipos abstractos de datos
requerimiento adicional sobre los elementos, que provoca un cambio en el pa-
rmetro del TAD: los elementos deben ser comparables.
Ejemplo de uso de colas prioritarias
Una cola prioritaria se puede utilizar para gestionar el orden de ejecucin de los trabajos en
un sistema multiusuario en el que el procesador se asigna segn la importancia de las tareas.
Por ltimo, introducimos el TAD de las listas con punto de inters (o, para
abreviar, listas), que representa el concepto ms general de secuencia: los ele-
mentos se pueden insertar en cualquier lugar de la secuencia, y se puede borrar
y consultar cualquier elemento. Con este objetivo se define TAD no como un
contenedor simple, sino como un contenedor recorrible. La herencia mltiple
nos permite plasmar este nuevo TAD de forma simple y elegante.
2.2.2. Los rboles binarios
El TAD de los rboles binarios, tal como se ha descrito, tiene un modelo com-
pletamente definido que se puede implementar segn diferentes estrategias
que veremos ms adelante.
Partiendo de este TAD, podemos definir una variante que consiste en aadirle
las operaciones de recorrido, heredando otra vez de ContenedorRecorrible. El re-
sultado es la clase de los rboles recorribles.
Observacin
En lugar de proponer la restric-
cin de comparacin sobre los
elementos, se podra haber re-
querido una funcin que, dado
un elemento, retornase su priori-
dad (un entero), y entonces se
podran comparar directamente.
Observad que
las dos operaciones de con-
sulta de las listas (heredadas
deContenedorRecorrible
y Secuencia) son la misma.
En realidad...
... las operaciones aade
y consulta de ColaPrioritaria no
ocultan las anteriores, que
siguen existiendo.
FUOC P01/75001/00075 21 Tipos abstractos de datos
Fijmonos en una diferencia con respecto a las listas: el punto de inters no se
considera relevante para las operaciones de construccin y destruccin del r-
bol, slo lo es para la consulta.
De hecho, esta clase an no determina cmo se obtienen los nodos del rbol,
dada la ausencia de restricciones; la clase todava est indefinida. Posterior-
mente veremos que existen varias polticas de obtencin de los elementos del
rbol; en consecuencia, decidimos introducir una clase para cada una, en las
que ya s aparecen las restricciones que determinan el orden.
Finalmente, para los casos en que sea necesario tratar un mismo rbol con va-
rios recorridos, definimos una ltima clase que los ofrece todos. Esta clase sim-
plemente hereda de todas las anteriores.
Hay que ir con cuidado con la herencia mltiple: si bien las operaciones de
posicionar, avanzar y preguntar por el final del recorrido se tienen que man-
tener separadas, no sucede igual con la consulta, que tiene el mismo com-
portamiento para todos los recorridos (acceder al elemento distinguido). La
forma correcta de tratamiento a este respecto depende del lenguaje (renom-
brar, prefijar, etc.).
FUOC P01/75001/00075 22 Tipos abstractos de datos
2.2.3. Los conjuntos
Distinguimos dos grandes categoras de conjuntos: los conjuntos como tales
y los conjuntos con repeticiones, a los que llamaremos sacos. En los prime-
ros, los elementos no pueden aparecer repetidos y, en los segundos, s. En los
sacos, la operacin de supresin elimina slo una aparicin de un elemento;
adems, la operacin de pertenencia se complementa con otra para contar el
nmero de apariciones de un elemento.
Como es habitual, sobre estos dos TAD podemos crear las versiones recorri-
bles. A diferencia de las estructuras lineales, el orden de obtencin de los ele-
mentos es aleatorio, y por eso distintas clases de implementacin de estos TAD
pueden tener un comportamiento diferente.
2.2.4. Las funciones
Ya hemos comentado que el TAD de las funciones plasma el concepto de fun-
cin parcial, y por eso la primera y ms inmediata especializacin es definir
por herencia las funciones totales.
Este nuevo TAD, el TAD de las funciones totales, exige que el alcance de la
funcin tenga un elemento especial, que es el resultado que se obtiene cuando
se consulta un elemento que no forma parte del dominio de la funcin. Por
este motivo, el parmetro de este TAD correspondiente al alcance es ElemEsp.
La operacin de existencia se mantiene, aunque ya no tiene la importancia de
antes; su resultado se puede calcular a partir de la consulta.
Las funciones totales son
interesantes porque aseguran
que la consulta siempre
da un resultado vlido.
FUOC P01/75001/00075 23 Tipos abstractos de datos
Otra variante del concepto de funcin (ya sea total o parcial) aparece cuando,
en lugar de relacionar elementos de dos dominios diferentes, uno de los dos
dominios est contenido en el otro*. Una visin equivalente es que la funcin
se convierte en un conjunto de elementos tales que cada elemento tiene una
clave que lo distingue. El vnculo entre los dos dominios se establece mediante
un parmetro f que, dado un elemento, retorna su clave. El conjunto con clave
se construye por herencia redefiniendo la funcin de insercin para que tenga
un nico parmetro, de clase ElemClave (que suministra la funcin f).
Por ltimo, mencionamos que existen varias versiones recorribles para estos TAD.
2.2.5. Las relaciones
Consideramos varias especializaciones del concepto de relacin:
1) La primera especializacin que hacemos de este concepto proviene de la
forma de tratar los dos dominios que lo forman. Como hemos comentado
* Por ejemplo, una funcin que,
dado el DNI de una persona,
proporciona la ficha completa
de sta, incluido el mismo DNI.
FUOC P01/75001/00075 24 Tipos abstractos de datos
anteriormente, la clase Relacin implica que cuando se crea la relacin se co-
nocen ambos dominios y permanecen invariables durante su vida. Sin embar-
go, ste no siempre es el caso. Para cada dominio, la otra situacin posible es
que, cuando se crea la relacin, el dominio est vaco y los elementos se ten-
gan que insertar y borrar explcitamente.
Por eso, definimos dos clases simtricas, considerando esta situacin en cada
uno de los dominios y, finalmente, una ltima clase heredera de estas dos, para
el caso de que los dos dominios sean variables. Las cuatro clases resultantes pue-
den considerarse como un punto de partida de cuatro subjerarquas paralelas
para las relaciones. Nosotros nos centraremos en la primera (los dos dominios
fijos), pero los resultados obtenidos se pueden generalizar al resto de los casos.
Actividad
Una alternativa que no hemos considerado es que implcitamente se vayan aadiendo y
borrando los elementos a medida que aparecen o desaparecen en la relacin.
1. Redefinid la jerarqua que cuelga de la clase Relacin considerando la alternativa que
acabamos de proponer.
2) El siguiente criterio de especializacin ms relevante es la asociacin de pe-
sos, llamados etiquetas, en las interrelaciones.
Las etiquetas, que deben presentar ciertas operaciones para manipularlas c-
modamente (la suma y las comparaciones), se definen en la clase ElemSum.
Motivos para la primera
especializacin de relacin
En el momento de relacionar
a los estudiantes y a las
estudiantes y a los tutores
y tutoras de la UOC, debemos
tener presente que los
primeros se matriculan
y se desmatriculan, mientras
que los segundos se pueden
desvincular de la universidad.
Ejemplo de asociacin de
pesos en las interrelaciones
El alumno puede evaluar a su
tutor y esta puntuacin sera la
etiqueta de la relacin.
FUOC P01/75001/00075 25 Tipos abstractos de datos
Como cambios importantes, aparte de la modificacin de la interfaz de la
operacin aade para incorporar las etiquetas, vemos que hay que aadir
una operacin de consulta de la etiqueta asociada a una interrelacin exis-
tente, y tambin la modificacin del resultado de la operacin de consulta de
los recorridos, para que no slo retorne un elemento del dominio que le corres-
ponda, sino tambin la etiqueta asociada (ste es el papel de la clase ElemYElem-
Sum). Este requisito resulta imprescindible para obtener un TAD suficientemente
verstil y adaptable a los algoritmos que lo usarn.
3) Las relaciones pueden ser simtricas. Es decir, el orden de los elementos in-
terrelacionados es irrelevante. Esto nos da nuevas clases en la subjerarqua.
Por ltimo, una especializacin bsica de las relaciones aparece cuando se requie-
re que todos los dominios sean el mismo. El resultado es el TAD de los grafos:
a) En un primer nivel de herencia, obtenemos el TAD de los grafos dirigidos.
Observamos que no se aade ninguna operacin; el nico cambio es la restric-
cin sobre los dominios.
b) Inmediatamente, podemos definir el TAD de los grafos dirigidos etique-
tados, aadiendo las etiquetas y con las modificaciones anteriormente men-
cionadas en este caso.
Ejemplo de grafo
Una red de ordenadores donde
siempre se relacionan pares de
ordenadores es un ejemplo
de grafo.
FUOC P01/75001/00075 26 Tipos abstractos de datos
c) El ltimo TAD que consideraremos es el TAD de los grafos no dirigidos eti-
quetados (el caso no etiquetado no se considera porque no es necesario en esta
asignatura), correspondientes a las relaciones simtricas. Aqu slo hay que re-
cordar la irrelevancia en el orden de los parmetros de las operaciones indivi-
duales sobre las interrelaciones.
En estos TAD sobre grafos, aadimos operaciones que realizan ciertos trabajos es-
pecficos: bsqueda de caminos mnimos (en grafos dirigidos y etiquetas) y cl-
culo de rboles de expansin minimales (en grafos no dirigidos y etiquetados).
Por lo que se refiere a los recorridos en el caso de los grafos, hay que decir que,
como en el caso de los rboles binarios, existen varias clases, aunque en la asigna-
tura slo veremos un tipo: la ordenacin topolgica que nos asegura que visitamos
todos los elementos del grafo en un orden determinado. Los grafos recorribles se
tendran que definir con la misma estrategia que en el caso de los rboles.
2.3. Traduccin de la jerarqua a Java
Cuando definimos la jerarqua, nos abstuvimos de utilizar el lenguaje de progra-
macin que se usa para implementar. Pensamos que sta es la mejor forma de ac-
tuar, porque nos permite separar el problema del diseo y de la implementacin
Consultad la ordenacin topolgica
de los rboles binarios en el mdulo
Secuencias y rboles de esta asignatura.
FUOC P01/75001/00075 27 Tipos abstractos de datos
de la jerarqua. Sin embargo, ahora es necesario ver cmo se plasma la jerar-
qua en el lenguaje que se usa en la asignatura, el lenguaje Java.
Quiz los dos obstculos ms importantes cuando se lleva a cabo la traduccin
son la ausencia en Java de dos mecanismos de estructuracin que hemos utiliza-
do profusamente: la genericidad y la herencia mltiple. Veamos primero cmo
solucionaremos estas ausencias, y despus hablaremos de otros detalles menos
importantes.
2.3.1. Simulacin de la genericidad
Si bien Java no ofrece la genericidad*, podemos aprovechar el hecho de que todas
las clases Java se consideran herederas de una superclase llamada Object. Enton-
ces, los contenedores se pueden definir sobre valores de clase Object, y el polimor-
fismo y la vinculacin dinmica permiten que en tiempo de ejecucin los Object
puedan tomar cualquier forma y se les puedan aplicar los mtodos adecuados.
La clase Object define unos cuantos mtodos que heredan todas las clases que
intervienen en un programa Java. Destacamos dos: el mtodo Clone para dupli-
car valores, yEquals, que permite comparar dos objetos de la clase. La presencia
de estos dos mtodos nos permite decir que Object es equivalente al parmetro
Elem con el que hemos definido los contenedores bsicos.
Sin embargo, tiene que quedar claro que la solucin que adoptamos presenta
ciertas diferencias con respecto a la genericidad:
1) Se pueden construir contenidos heterogneos donde se mezclen elementos
de varias clases, dado que, por las reglas de control para la correccin del tipo
de la orientacin a objetos, cualquier clase heredera de Object (y todas lo son)
puede entrar en el contenedor.
2) La clase Object no ofrece algunas de las funciones que algunos contenedo-
res necesitan ms adelante. Se podra pensar en la creacin de una subjerar-
qua de Object, pero entonces tambin se podran encontrar problemas por la
ausencia de herencia mltiple.
3) Como su nombre indica, los elementos del contenedor deben ser objetos
de clase, y ste no es el caso habitual de valores de tipos predefinidos. Cuando
stos se quieren usar como instancias de Object, hay que transformar previa-
mente los valores en objetos de las clases respectivas.
2.3.2. Simulacin de la herencia mltiple
Java no soporta la herencia mltiple en las clases, pero no es el nico lenguaje
orientado a objetos que presenta este inconveniente. Afortunadamente, pode-
mos usar las interfaces de Java para simularla.
* C++ y Eiffel son lenguajes OO
que ofrecen genericidad.
Consultad laspeculiaridadesde los
mtodosClone y Equal en el
subapartado 6.3. de este mdulo didctico.
Consultad la diferencia entre los
valores de tipos predefinidos y los
objetos de clase que habis estudiado
en la asignatura Fundamentos de
programacin II.
FUOC P01/75001/00075 28 Tipos abstractos de datos
Recordad que las interfaces son clases en las que todos los mtodos son virtua-
les. Dada esta caracterstica, podemos usar las interfaces como un mecanismo
de Java para implementar clases de especificacin. Es decir, todos los TAD de la
jerarqua que hemos visto en este apartado se traducen como interfaces Java.
Las propiedades importantes de las interfaces son las que mencionamos a con-
tinuacin:
a) Una interfaz puede heredar de ms de una interfaz; es decir, las interfaces
s tienen herencia mltiple.
b) Una clase puede implementar una o ms interfaces. Volveremos a este pun-
to ms adelante.
c) Una clase puede implementar slo parcialmente una o ms interfaces.
d) Una clase slo puede heredar de otra clase, independientemente de si im-
plementa interfaces o no.
En el caso de conflictos de nombres de una clase o interfaz que implementa y/o
hereda de ms de una, la poltica es la siguiente:
si se hereda ms de una vez un smbolo con el mismo nombre y parme-
tros, se consideran iguales;
si se hereda un smbolo con el mismo nombre pero parmetros diferentes,
se consideran diferentes.
El gran inconveniente de usar interfaces es la imposibilidad de definir atribu-
tos o implementar mtodos.
Imposibilidad de definir atributos o implementar mtodos en Java
La interfaz para la clase Contenedor resulta de la siguiente manera:
No se puede definir el atributo tamao, ni implementar los mtodos nbElems ni vaco?,
tal como hemos hecho en la jerarqua mediante restricciones.
La herencia mltiple entre contenedores se ilustra en la clase ContenedorRecorri-
ble, que resulta:
public interface Contenedor {
public boolean vacio?();
public int nbElems();
}
public interface ContenedorRecorrible
extends Contenedor, Iterador {
}
Consultad las interfaces introducidas
en la asignatura Fundamentos
de programacinII.
Consultad la implementacin de ms
de una interfaz para una sola clase en
el apartado 3 de este mdulo didctico.
FUOC P01/75001/00075 29 Tipos abstractos de datos
2.3.3. Otras cuestiones
Aparte de los aspectos enunciados en el subapartado anterior, citemos tam-
bin los siguientes:
1) Las operaciones constructoras deben tener el mismo nombre de la clase; si
hay ms de una, diferirn en el nmero y/o tipo de parmetros. Esto afecta a
todas las operaciones de creacin, crea, que desaparecen en Java.
2) No hay operaciones de destruccin porque la gestin que Java hace de la
memoria dinmica (es decir, del espacio ocupado por los objetos) destruye au-
tomticamente los objetos.
La memoria dinmica se estudia
con detalle en el apartado 6 de este
mdulo didctico.
FUOC P01/75001/00075 30 Tipos abstractos de datos
3. Implementacin de TAD
Una vez se dispone de la signatura de un TAD, es el momento de disear im-
plementaciones adecuadas que posibiliten la participacin activa en la ejecu-
cin de los programas, por medio de la utilizacin de un determinado lenguaje
de programacin (orientado a objetos o imperativo).
Laimplementacin de un TAD consta de tres partes:
1) Primero hay que decidir la representacin del TAD, es decir, la estrategia de
representacin de sus valores. En el contexto en que nos movemos, elegir la re-
presentacin del TAD significa decidir un mtodo de almacenamiento de los ele-
mentos del contenedor y representarlo mediante atributos privados de la clase.
2) A continuacin, hay que establecer las relaciones entre estos atributos me-
diante el invariante de la representacin, que identifica todos los estados
admisibles de los objetos de la clase. El invariante consistir en un predicado
booleano, expresado en lenguaje formal o en lenguaje natural (o mezclando
ambos estilos), y su efecto es puramente documental. Para destacar su nece-
sidad, de ahora en adelante consideramos que el invariante de la representa-
cin forma parte de la representacin misma.
3) Por ltimo, conviene escribir algoritmos que codifiquen cada una de las
operaciones del TAD. Cada algoritmo debe usar los atributos de la clase, tanto
para consultarlos como para modificar su valor, y puede invocar mtodos de
otras clases con las que tiene establecida una relacin de uso.
Como se podr ver a lo largo de la asignatura, dado un TAD no existe una nica
implementacin posible, sino muchas (potencialmente infinitas). Una imple-
mentacin puede adaptarse mejor que las otras en un contexto de utilizacin
del TAD, pero puede llegar a ser inadecuada en otros contextos. Por este motivo,
una librera de componentes verstil tendr que ofrecer varias implementacio-
nes de un mismo TAD, de forma que posibilite el uso eficaz en el mximo n-
mero de contextos posibles.
En la escritura de implementaciones se plasma una notacin algortmica inde-
pendiente del lenguaje de programacin concreto. En este caso, los tipos pre-
definidos, constructores de tipos, expresiones e instrucciones se usan con la
sintaxis que ya conocis de otras asignaturas, con las pequeas modificaciones
de notacin exigidas por el cambio de paradigma de programacin (de impe-
rativo a orientado a objetos). Toda la implementacin se encapsula en una cla-
se, en la que hacemos constar el nombre y la clase que encapsula la definicin
del TAD que se implementa.
El invariante en otros
lenguajes OO
Hay lenguajes, como Eiffel, que
permiten escribir invariantes
que se pueden evaluar opcio-
nalmente en tiempo de ejecu-
cin, durante la depuracin del
programa.
En el apartado 4 de este mdulo
didctico se incidir en el problema
de la evaluacin de las implementaciones,
y en el apartado 5 veris ya unas cuantas
estrategias de implementacin de uso
comn.
Recordad la sintaxis de la notacin
algortmica utilizada en la asignatura
Fundamentos de programacin I.
FUOC P01/75001/00075 31 Tipos abstractos de datos
3.1. Representacin del TAD
En este subapartado veremos con detalle en qu consiste la representacin de
un TAD.
3.1.1. Los atributos del TAD
Como ya hemos dicho, la primera parte del proceso consiste en elegir unos
atributos que permitan representar todos los valores posibles del contenedor.
Por eso, podemos usar todos los tipos predefinidos y constructores de tipo que
pone a nuestro alcance el lenguaje de programacin elegido, que recogemos
en la notacin algortmica.
Recapitulemos aqu el abanico de elementos de este tipo que ponen a nuestro
alcance los lenguajes ms habituales, mencionando su implantacin en Java:
1) El tipo de los booleanos (disponible en Java).
2) Los tipos numricos, concretados en varias clases de nmeros enteros y
reales. En Java disponemos de cuatro tipos de nmeros enteros (byte, short, int
y long) y dos reales (float y double), que difieren en el nmero de bits utilizados
en su representacin.
3) El tipo de los caracteres. En Java se tiene el cdigoUnicode, extensin del ASCII.
4) El tipo de la cadena de caracteres (strings), tambin disponible en Java.
5) El constructor de tipos de los vectores. Todo lenguaje de programacin
ofrece de un forma u otra este constructor, imprescindible para almacenar co-
lecciones de elementos, y tambin lo hace Java, con ciertas peculiaridades des-
critas detalladamente en la asignatura Fundamentos de programacin II.
6) El constructor de tipos de las tuplas, para representar agregaciones de da-
tos. Este constructor, normal en los lenguajes imperativos, desaparece en mu-
chos lenguajes orientados a objetos, especialmente en los llamados lenguajes
OO puros, entre los cuales se encuentra Java. El motivo es que los atributos de
una implementacin se interpretan implcitamente como una tupla. Por mo-
tivos de comodidad conservamos las tuplas en la notacin algortmica utiliza-
da en esta asignatura.
La ausencia de tuplas exige introducir clases auxiliares, como podis compro-
bar en las implementaciones en Java de la jerarqua.
3.1.2. El invariante de la representacin
Una vez elegidos los atributos que permiten representar los valores del TAD,
el siguiente paso consiste en escribir el invariante que identifica los estados v-
lidos en los que se puede encontrar un objeto.
Lostipospredefinidosy constructores
de tipo se han introducido en las
asignaturasFundamentos de programacin
I y Fundamentos de programacin II.
Observacin
Hay unas cuantas construccio-
nes secundarias que no se
presentan aqu, como el tipo
por enumeracin, el tipo
subrango, etc.
Consultad el constructor de tipo
de vectores en la asignatura
Fundamentos de programacin II.
Podis recordar la definicin
de lenguaje puro orientado
a objetos en el material de
Fundamentos deprogramacin II.
Consultad la escritura de
implementacionesen Java en el
subapartado 3.3. de este mdulo didctico.
FUOC P01/75001/00075 32 Tipos abstractos de datos
El invariante de la representacin toma la forma de un predicado booleano
que deja explcitas las relaciones entre estos atributos. Cualquier objeto de la
clase que encapsula el TAD tiene que satisfacer este predicado. Obviamente,
esta exigencia no se mantiene durante la ejecucin de un mtodo, momento
en el que el invariante se puede violar temporalmente mientras el mtodo ac-
ta; pero se exige que cuando se acabe la ejecucin del mtodo, el invariante
se vuelva a cumplir.
Idealmente, el predicado booleano ser una formula en lgica de primer orden
que involucrar a los atributos de la clase implementada y a los mtodos de otras
clases; tambin se usarn expresiones propias de la notacin algortmica y, even-
tualmente, se pueden introducir predicados auxiliares. Ahora bien, dado el carc-
ter documental de esta construccin, tambin es lcito expresar informalmente
todo el invariante o parte del mismo, especialmente en aquellas partes en las que
la notacin lgica es suficientemente densa como para no entenderla.
3.2. Codificacin de las operaciones
Para escribir el cdigo de las operaciones introducidas en la signatura del TAD,
podemos utilizar las instrucciones y expresiones habituales que ya conocis.
Slo hay que destacar que a lo largo de esta asignatura usaremos en ocasiones
un concepto nuevo asociado a las diferentes construcciones iterativas, el con-
cepto de invariante del bucle.
El nombre ya denota una similitud con la nocin deinvariante de representacin
y, efectivamente, esta similitud tiene lugar. As como el invariante de la repre-
sentacin indica las combinaciones de valores vlidos de los atributos de la
clase, el invariante del bucle denota las combinaciones de valores vlidos de
los atributos y objetos auxiliares que intervienen en el bucle.
El invariante de la representacin siempre forma parte implcitamen-
te de la precondicin y postcondicin de toda operacin pblica o pro-
tegida del TAD.
La idea fundamental es que, independientemente de si usamos una no-
tacin formal, semiformal o totalmente informal, una clase de imple-
mentacin siempre debe incluir el invariante de la representacin.
El invariante del bucle es un predicado booleano que se debe cumplir
cuando se empieza y se acaba la ejecucin del bucle, as como justo an-
tes de entrar y salir.
Lgica de primer orden
La lgica de primer orden
permite escribir frmulas con
literales, variables, operadores
variados (negaciones, conjun-
ciones, disyunciones, implica-
ciones y equivalencias) y unos
cuantos cuantificadores (uni-
versal y existencial sobre todo,
pero tambin sumatorios y
el llamado cuantificador de
recuento). Si tenis problemas
con la notacin utilizada, po-
dis consultar los apuntes
Introduccin a la lgica
en el material asociado
de la asignatura.
Consultad las expresiones
e instrucciones habituales de
las asignaturas Fundamentos
de programacin I y Fundamentos
de programacin II.
El invariante del bucle
en otros lenguajes OO
Una vez ms, Eiffel es el
lenguaje comercial que
implementa el concepto
de invariante del bucle
en tiempo de ejecucin.
Otros lenguajes lo pueden
simular mediante construccio-
nes de asercin (instrucciones
que se pueden usar en cualquier
punto de un programa para
comprobar si una condicin
se cumple).
FUOC P01/75001/00075 33 Tipos abstractos de datos
No acaban aqu las similitudes. Tambin en los bucles el invariante tiene prop-
sitos esencialmente documentales, si bien hay algn lenguaje que permite su uso
en tiempo de ejecucin. La sintaxis es la misma que en el invariante de la repre-
sentacin. Y tambin se permite su escritura informal. Ahora bien, a diferencia
de los otros, no siempre escribimos los invariantes de los bucles, sino slo cuan-
do pensamos que aportan informacin til. Esto pasar especialmente en los al-
goritmos de grafos y en algn tipo de rboles, en los que el cdigo tiene cierto
grado de complicacin y se considera que el invariante ayuda a su comprensin.
El otro punto relevante de la notacin algortmica tiene que ver con la encapsula-
cin de las operaciones. Dado el paradigma en el que nos encontramos, las opera-
ciones de la signatura del TAD se encapsulan en mtodos que actan siempre sobre
un objeto; mtodos que eventualmente sern funciones, si retornan algn valor.
Pese a esto, si durante el proceso de codificacin de los mtodos se introduce
alguna operacin auxiliar (privada de clase), se puede elegir entre definirla tam-
bin como mtodo (si acta sobre el objeto completo) o como una funcin o
accin parametrizada desligada de los objetos de clase (si acta sobre un sub-
conjunto de los atributos de la clase), con parmetros de entrada, de salida y de
entrada y salida. Por ejemplo, un mtodo de insercin sobre un contenedor
que tiene un vector como atributo puede utilizar una funcin auxiliar para
comprobar si el valor insertado ya est dentro del vector.
Por ltimo, recordemos que las operaciones tienen una precondicin o post-
condicin que, a veces, y cuando sea relevante, haremos explcitas, especial-
mente por lo que se refiere a la precondicin.
En las implementaciones presentadas en esta asignatura supondremos que
una operacin se llama cuando se cumple su precondicin, de forma que no
se comprobarn explcitamente las condiciones de error y, en consecuencia,
no se usar ningn tipo de mecanismo de excepciones para tratarlas.
3.3. Escritura de implementaciones en Java
Ya hemos comentado que las clases de implementacin en Java toman la forma
de clases que implementan una o ms interfaces. Dentro de la clase incluimos
como atributos privados todos aquellos atributos necesarios para representar el
tipo, que sern de tipo predefinido o de clases construidas por el usuario a par-
tir de los constructores de tipo de Java.
Ya hemos hablado de los tipos predefinidos. Por lo que se refiere a los construc-
tores de tipos, tambin hemos comentado la existencia de vector y la inexisten-
cia de tuplas. Sobre este ltimo punto hablaremos ahora.
Si bien en el primer momento puede parecer que las tuplas no son necesarias,
dado que los atributos de la clase se pueden interpretar como campos de una
Hay que tener presente
que los lenguajes orientados
a objetos puros no permitirn
implementar directamente
funciones y acciones al estilo
imperativo, y se necesitar una
traduccin a mtodo. Incluso
considerando esta traduccin,
permitimos este tipo de accio-
nes y funciones imperativas
dada la simplificacin
resultante del cdigo
en algunas situaciones.
Consultad los tipos predefinidos en
el subapartado 3.1.1. de este
mdulo didctico.
FUOC P01/75001/00075 34 Tipos abstractos de datos
tupla que representa el TAD, en realidad la necesidad aparece cuando conside-
ramos la tpica situacin en que tenemos vectores de tuplas. Si no hay tuplas
en Java, cmo podemos declarar estos vectores?
La solucin consiste en declarar una clase auxiliar, que puede ser interna a la
clase principal, que tenga como atributos los campos de tupla. Esta clase juega
un papel de tupla, y la clase principal puede acceder a sus atributos desde cual-
quier punto.
Ejemplo de vector de tuplas
Aqu tenemos un extracto de una clase que define un vector de tuplas de pares de enteros:
Tambin es importante destacar la existencia de una clase llamada Vector, que
podemos utilizar en las implementaciones de TAD con vectores, que define un
mtodo seguro de trabajo con este constructor de tipos. En concreto, esta clase
permite que el vector crezca durante la ejecucin del programa, si se llena, y
tambin suministra unos cuantos mtodos de inters para manejar los objetos
vectores.
Por lo que se refiere a instrucciones en Java, no es necesario aadir nada ms,
ya que todo lo que podamos decir a partir de ahora ya lo conocis de la asig-
naturaFundamentos de programacin II.
class T implements I {
class Node {
public int x, y;
}
private Node A[];

El paquete java.util proporciona


la clase Vector.
FUOC P01/75001/00075 35 Tipos abstractos de datos
4. Eficiencia de las implementaciones
En el apartado anterior hemos aprendido las herramientas que nos permitirn
construir implementaciones de los TAD. En el caso general, para cada TAD exis-
ten varias implementaciones interesantes, que se adaptan a los diferentes con-
textos habituales de utilizacin del tipo. El problema que surge inmediatamente
es el de tener unos criterios para medir las implementaciones que nos permitan
estudiar su adecuacin.
Uno de los criterios fundamentales en la medida de una implementacin es
conocer el aprovechamiento que hace de los recursos del ordenador, especial-
mente si consideramos el espacio que ocupa un objeto del tipo y la velocidad
de ejecucin de sus operaciones.
Este criterio se conoce con el nombre de eficiencia de la implementacin, y
su estudio es el objetivo de este apartado:
Laeficiencia de la implementacin se mide utilizando alguna estrategia so-
bre la que podamos pedir varias condiciones:
1) Tiene que ser totalmente objetiva, es decir, calculable a partir de unas re-
glas deterministas. Este requisito es especialmente importante para asegurar la
fiabilidad del resultado del estudio.
2) Se tiene que basar en un anlisis del cdigo y no en pruebas de ejecucin.
No slo los resultados obtenidos sern siempre ms exactos, sino que tambin
se puede llegar a descartar una implementacin si la medida da malos resulta-
dos, antes de codificarla.
3) Tiene que ser independiente de la mquina que ejecutar el cdigo. Por este
motivo, la medida en tiempo absoluto de ejecucin (fracciones de segundos) no
es la indicada, como tampoco lo es la medida del espacio en mltiplos de bytes.
4) Tiene que ignorar factores constantes que los avances tecnolgicos acaban
superando. Aqu tenemos otra razn que descarta las unidades mencionadas
en el punto anterior.
5) Tiene que considerar la dimensin de los datos de entrada. Por ejemplo, si
tenemos que decir cunto tarda un algoritmo de ordenacin, es natural dar el
resultado en funcin de la longitud del vector que se debe ordenar.
6) Tiene que considerar los grandes volmenes de datos, porque es cuando las
diferencias que se pueden dar entre las distintas alternativas llegan a ser real-
mente importantes.
En el apartado 5 de este mdulo
didctico se introducen dosgrandes
estrategiasde implementacin de losTAD.
Cada una de estasestrategiaspara un TAD
particular puede dar lugar a tcnicasde
implementacin msconcretas.
Necesidad de medir
las implementaciones
Medir las implementaciones
es necesario, no slo porque
el saber no ocupa lugar, sino
tambin para comparar
las distintas implementaciones
existentes. Salvo raras excep-
ciones, no existe la mejor
implementacin en trminos
absolutos, sino la mejor
implementacin para unos
determinados requisitos de uso.
FUOC P01/75001/00075 36 Tipos abstractos de datos
Una aproximacin consolidada que responde a estas caractersticas es la fami-
lia de las llamadas notaciones asintticas.
As pues, como decimos, se trata de una familia de notaciones y no de una no-
tacin nica. No discutiremos aqu las posibles opciones dentro de la familia.
Slo diremos que elegimos la llamada O-grande, que calcula la eficiencia en
el peor de los casos (cuando el TAD se comporta de la peor manera posible con
respecto a este criterio). Esta opcin es ms prudente y comporta un anlisis
ms sencillo de los algoritmos que las otras alternativas existentes, que estu-
dian el mejor de los casos o el caso medio.
O(f ) es el conjunto de las funciones para las quef es, asintticamene, una cota
superior. Es decir, a partir de cierto punto n
0
, slo hay que multiplicar f por
una constante c
0
para conseguir que el valor de las funciones g est siempre
por debajo del valor de f. La siguiente figura ilustra la definicin:
Os puede parecer que, gracias a la ayuda que damos a f multiplicndola por
c
0
, la podemos hacer superior a cualquier otra funcin, pero esto no es cierto.
Por ejemplo, si f(n) =n y g (n) =n
2
, g siempre llegar a superar a c
0
f a partir de
algn punto, por grande que sea c
0
.
Las notaciones asintticas no intentan establecer el tiempo exacto de
ejecucin o el espacio exacto ocupado, sino que caracterizan estas mag-
nitudes mediante una funcin sobre el volumen de los datos de entrada.
La funcin surgir de un anlisis de los constructores de tipos (vectores,
apuntadores, etc.) y las instrucciones dadas en la implementacin, y su
definicin se centra en los grandes volmenes de datos de entrada.
Ladefinicin de O-grande, abreviada O, es:
O(f ) = {g | c
0
R
+
: n
0
N
+
: (n n
0
: g(n) c
0
f(n))}
Eficiencia
La eficiencia, tal como se
define aqu, no slo sirve para
medir TAD, sino para medir en
general cualquier entidad de
software, como un algoritmo
de ordenacin.
R
+
y N
+
representan los nmeros
reales y naturales positivos
respectivamente.
FUOC P01/75001/00075 37 Tipos abstractos de datos
Ms all de la lectura matemtica, hay que comprender su objetivo. Dado el al-
goritmo o representacin de tipo que queremos evaluar, obtendremos como efi-
ciencia (aplicando unas reglas que ya veremos) una funcin g de n, donde n es
la dimensin de los datos de entrada. Esta g pertenecer a O(f) para una f dada
que caracterice la eficiencia del algoritmo o representacin.
Para la mayora de los algoritmos de esta funcin, f estar dentro de una de las
siguientes categoras:
Constante: f(n) =k, para k N
+
. Este coste se representa mediante O(1). Es
tpico encontrarlo en algoritmos que son secuencias de asignaciones de va-
lores de tipos simples.
Logartmica: f(n) =logn. Este coste se representa mediante O(logn). Encon-
tramos este coste en algoritmos muy especiales (por ejemplo, en investiga-
ciones dicotmicas y en distintos algoritmos de tratamiento de rboles).
Lneal*: f(n) =n. Este coste se representa por O(n). Aparece con frecuencia
en algoritmos que tienen un bucle simple o en representaciones que tienen
algn vector como atributo.
Cuasi-lineal*: f(n) =n log n. Este coste se representa por O(n log n).
Cuadrtica*: f(n) =n
2
. Este coste se representa por O(n
2
). Surge sobre todo
en algoritmos con dos bucles anidados o vectores bidimensionales.
Cbica*: f(n) =n
3
. Este coste se representa por O(n
3
). En este contexto, se
tiene este coste para tres bucles anidados o vectores tridimensionales.
Exponencial*: f(n) =k
n
. Este coste se representa mediante O(k
n
), para k N
+
.
Se asocia a algoritmos que se basan en ir ensayando soluciones a un proble-
ma hasta encontrar la buena.
Estas categoras estn ordenadas de mejor (menos tiempo o espacio) a peor.
Tambin pueden aparecer otras, bsicamente las siguientes:
En general, polinmica de grado k: f(n) =n
k
.
f(n) =n
k
log n, que es peor que n
k
pero mejor que n
k+1
.
Una vez establecida la categora que corresponde a varias alternativas de im-
plementacin, la ordenacin de las categoras nos da la ordenacin de las imple-
mentaciones. Generalmente, los costes peores que los polinmicos, como el
exponencial o n
n
, se consideran inaceptables. Incluso funciones polinmicas de
grado elevado pueden representar alternativas demasiado costosas. La diferencia
* Por ejemplo, la bsqueda
de un elemento en un vector
ordenado.
* Por ejemplo, varios mtodos
eficientes de ordenacin
de vectores.
* Por ejemplo, un mtodo
de suma de matrices.
* Por ejemplo, un mtodo
de multiplicacin de matrices.
* Por ejemplo, buscar una
asignacin de valores que haga
que una frmula sea cierta.
FUOC P01/75001/00075 38 Tipos abstractos de datos
entre estas categoras queda patente en la siguiente tabla, que da el valor de la fun-
cin representativa para diferentes volmenes de datos:
Tambin hay que decir que, a veces, existe ms de un tipo de informacin y, en-
tonces, pueden surgir variasn
1
, n
2
, n
k
. En este caso, la funcin f(n
1
, , n
k
) ser
generalmente una expresin aritmtica que combina todas estas magnitudes.
En el resto del apartado nos centramos en el clculo de la eficiencia de las ope-
raciones y representaciones de tipos.
4.1. Eficiencia temporal
Para determinar la categora que corresponde a la funcin de tiempo de un al-
goritmo, utilizaremos las reglas que enumeramos a continuacin:
1) El acceso a un atributo o posicin de vector de tipo predefinido y las operaciones
aritmticas y booleanas tienen el coste O(1); una referencia a un objeto, tambin.
2) La evaluacin de una expresin tiene el coste de evaluar sus subexpresiones
ms el coste que corresponda al operador op ms externo:
T(op x) = T(x) + T(op)
T(x op y) = T(x) + T(y) +T(op).
3) El coste de una composicin secuencial de instrucciones es la suma de los
costes de las instrucciones compuestas:
T(i1; i2) = T(i1) + T(i2).
n O( 1) O( log n) O( n) O( n log n) O( n
2
) O( n
2
log n) O(n
3
) O( 2
n
)
1 1 1 1 1 1 1 1 2
10 1 2,3 10 23 100 230 1.000 1.024
100 1 4,6 100 460 10.000 46.000 10
6
1,26 10
30
1.000 1 6,9 1.000 6.900 10
6
6,9 10
6
10
9

10.000 1 9,2 10.000 92.000 10
8
9,2 10
8
10
12

100.000 1 11,5 10
5
11,5 10
5
10
10
11,5 10
10
10
15

Lafuncin de eficiencia temporal T(x) denota el tiempo de ejecucin
del fragmento de cdigo x medido con la notacin O.
En la tabla
se constata que la diferencia
entre las categoras se hace
ms importante a medida que
el volumen de datos es mayor.
Ejemplo de informacin
variada
Un ejemplo en el que consta
ms de un tipo de informacin
sera el espacio de un contene-
dor que almacenase alumnos
y asignaturas.
Al final de este subapartado
encontraris un ejemplo de
aplicacin de estas reglas.
FUOC P01/75001/00075 39 Tipos abstractos de datos
4) El coste de la asignacin es el de la evaluacin de las expresiones que apa-
recen ms el de transferencia de los datos, que corresponde a su dimensin:
T(x := y) = T(x) + T(y) + E(x).
5) El coste de una instruccin alternativa es la suma de los costes de evaluar
la expresin y ejecutar las dos ramas:
T(si e entonces i1 sino i2 fsi) = T(e) + T(i1) + T(i2).
6) El coste de una invocacin a mtodo es el de la evaluacin de las expresiones
que se pasan como parmetros ms el del coste de la accin o funcin invocada:
T(f(p
1
, , p
n
)) = T(f ) + (k: 1 k n: T(p
k
)).
7) El coste de una instruccin iterativa se puede calcular de dos formas:
a) Multiplicando el nmero de vueltas por el coste de una vuelta. Este mtodo
est indicado cuando todas las vueltas tienen el mismo coste:
T(mientras ehacer i fmientras) = Nmero de vueltas (T(e) + T(i)).
b) Sumando el coste de todas las vueltas ejecutadas:
T(mientras e hacer i mientras) = k: 1 k Nmero de vueltas:
(T(e) + T(i) en la vuelta k).
Aparte de estas reglas de notacin asinttica, puede ser til usar alguna de las
siguientes propiedades:
a) O(c f(n)) =O(c+ f(n)) =O(f(n)), para c constante.
b) c O(f(n)) =c + O(f(n)) =O(f(n)), para c constante.
c) f(n) O(g(n)) =O(f(n) g(n)).
d) O(f(n)) + O(g(n)) =O(f(n) + g(n)) =O(mx(f(n), g(n))). Una consecuencia de
ello es: O(1) +O(f(n)) =O(f(n)). Y una extensin de esto es O(f(n
1
) + g(n
2
)) =
=O(mx(f(n
1
), g(n
2
))).
Ejemplos de clculo de costes
Considerad algunos ejemplos presentados en relacin con cada una de las propiedades
que acabamos de exponer:
a) O(5 n) =O(n); O(6 + n
2
) =O(n
2
).
b) 5 O(n) =O(n).
c) n O(n) =O(n n) =O(n
2
).
d) O(n) + O(n
2
) =O(n
2
); O(1) + O(1) =O(1).
e) n
1
>> n
2
O(f(n
1
) + g(n
2
)) =O(f(n
1
)), siempre y cuando g no sea exponencial.
El coste de asignacin
en lenguajes OO
En la mayora de los lenguajes
orientados a objetos, Java
entre stos, el coste de la asig-
nacin siempre ser O(1),
porque en realidad no asignan
objetos, sino referencias a los
objetos.
Consultad la definicin de E(x) como
el espacio de un dato en el
subapartado 4.2. de este mdulo didctico.
En los bucles por,
el coste T( e) es O(1).
Nos referimos a estas
propiedades como propiedades
de la notacin O .
FUOC P01/75001/00075 40 Tipos abstractos de datos
Ejemplo de uso de las reglas de evaluacin de la eficiencia temporal
Veamos con un ejemplo cmo podemos utilizar las herramientas para determinar el cos-
te del algoritmo de bsqueda en un vector que se han explicado en este subapartado:
Primero mostramos una explicacin resumida y, a continuacin, el detalle de la aplica-
cin, y de las reglas y propiedades vistas.
Puesto que el algoritmo es una composicin secuencial, su coste es la suma de costes de
las instrucciones, esto es, el mximo.
Las instrucciones son dos asignaciones de tipo predefinido (de coste constante, tal como
establecen la primera y segunda lnea) y un bucle. Dado que el coste constante es el me-
nor posible, el coste del bucle determina el coste del algoritmo.
Para encontrar el coste del bucle, observamos que el nmero de vueltas que haremos en el
peor de los casos es n (cuando el elemento no se encuentra o se encuentra en ltima posi-
cin), y que el coste de cada vuelta es igual al coste de la instruccin alternativa. El coste
de la alternativa, tal como indica la regla correspondiente, es igual a la suma (es decir, al
mximo) de los costes de evaluar la expresin y las dos ramas. Estos tres costes individuales
son O(1), de forma que el coste del bucle es n O(1) = O(n) (esta ltima igualdad para la
propiedad c de la notacin O), y ste es el coste final del algoritmo. En otras palabras, el
coste temporal del algoritmo de bsqueda es lineal con respecto a la dimensin del vector.
1) La primera regla que hay que aplicar es la 3, porque el algoritmo es una composicin
secuencial de tres instrucciones: las dos asignaciones iniciales y el bucle mientras. Si apli-
camos la regla 3 y T(alg) denota el tiempo de ejecucin del algoritmo, T(Li) el tiempo de
ejecucin de la lnea i del algoritmo y T(Li-Lj), el tiempo de ejecucin del bloque com-
prendido entre las lneas i y j, obtenemos la siguiente expresin:
T(alg) =T(L1) +T(L2) +T(L3-L7).
2) Para conocer la eficiencia de L1 y L2 procedemos, en ambos casos, de la misma forma.
Nos centramos en L1, y para L2, el proceso es idntico.
Aplicamos la regla 4, que es la regla de la asignacin, y se obtiene esta expresin:
T(L1) =T(tr) +T(fals) +E(tr).
Los dos primeros factores se obtienen con la regla 1 porque son variables y valores de tipo sim-
ple. Por otro lado, para el clculo para la eficiencia espacial, E(tr), podis consultar el subapar-
tado 4.2, donde veris que hay que aplicar la regla 1 (espacio de un dato de tipo predefinido).
En los tres casos, el coste resultante es O(1). Sustituimos y se obtiene:
T(L1) =O(1) +O(1) +O(1).
A continuacin aplicamos la propiedad d de la notacin O, que indica que la suma de
expresiones O es igual al mximo de los sumandos. Dado que en este caso todos los su-
mandos son iguales, obtenemos el siguiente resultado:
T(L1) =O(1) +O(1) +O(1) =O(1).
v: vector [1..n] de entero /* vector en el que se hace la bsqueda */
x: entero /* valor que se tiene que buscar */
tr: booleano /* indica si se tiene que encontrar o no */
i: entero /* si se ha encontrado, da la posicin */
(L1) tr := falso O(1) = O(1)
(L2) i := 1 O(1) = O(1)
(L3) mientras tr i n hacer O(1) + O(1) = O(1)
(L4) si v[i] = x entonces tr := cierto O(1) + O(1) = O(1) +
(L5) sino i := i + 1 O(1)
(L6) fsi
(L7) fmientras n O(1) = O(n)
O(n)
FUOC P01/75001/00075 41 Tipos abstractos de datos
3) Ahora estudiaremos T(L3-L7). Este fragmento de cdigo es un bucle; por tanto, aplica-
mos la regla 7. Hay dos variantes; aqu tomamos la variante a porque el coste de cada
vuelta del bucle tiene siempre la misma expresin. Fijmonos en que el nmero de vuel-
tas es, en el peor de los casos, n:
T(L3-L7) =n (T(tr i n) +T(L4-L6)).
Estudiamos el valor de los dos costes que han aparecido:
a) Por lo que se refiere al primero, es una expresin y, por eso, es necesario aplicar la regla 2:
T(tr i n) =T(tr) +T(i n) +T().
Aplicamos de nuevo la regla 2 para las dos subexpresiones que han aparecido:
T(tr i n) =(T(tr) +T()) +(T(i) +T(n) +T()) +T().
Todos estos costes son O(1) por la regla 1, porque las variables que aparecen son de tipo
predefinido (booleanas y enteras), as como los operadores son booleanos/relacionales.
As:
T(tr i n) =O(1) +O(1) +O(1) +O(1) +O(1) +O(1).
Aplicamos la propiedad ya conocida de simplificacin de la suma y resulta:
T(tr i n) =O(1) +O(1) +O(1) +O(1) +O(1) +O(1) =O(1).
b) Ahora estudiamos el segundo factor del bucle. Dado que es un condicional, aplicamos
la regla 5 y obtenemos la siguiente expresin:
T(L4-L6) =T(v[i] =x) +T(tr :=cert) +T(i :=i +1).
El primero trmino se soluciona con la regla 2 de clculo de expresiones, que ya hemos
utilizado en un par de ocasiones:
T(v[i] =x) =T(v[i]) +T(x) +T(=).
Todos estos costes son O(1) por la regla 1, porque tenemos una posicin de vector de tipo
predefinido, una variable entera y una operacin relacional. Si sobre el resultado aplica-
mos la propiedad de simplificacin de la suma, llegamos al siguiente resultado:
T(v[i] =x) =O(1) +O(1) +O(1) =O(1).
Los trminos segundo y tercero son asignaciones y hay que aplicar la regla 4, con tratamiento
similar, que abreviamos un poco (como siempre, aplicamos la simplificacin de la suma):
T(tr :=cierto) =T(tr) +T(cierto) +E(tr) =O(1) +O(1) +O(1) =O(1);
T(i :=i +1) =T(i) +T(i +1) +E(i) =T(i) +T(i) +T(1) +T(+) +E(i) =
=O(1) +O(1) +O(1) +O(1) +O(1) =O(1).
Despus de sustituir y aplicar la propiedad de la suma, llegamos al siguiente resultado:
T(L4-L6) =T(v[i] =x) +T(tr :=cierto) +T(i :=i +1) =O(1) +O(1) +O(1) =O(1).
4) As pues, ya podemos calcular el coste del bucle. Primero aplicamos la propiedad d de
la notacin y despus, la propiedad c, y obtenemos:
T(L3-L7) =n (O(1)) +O(1)) =n O(1) =O(n).
5) Ahora ya tenemos los tres trminos de la expresin de coste de partida:
T(alg) =T(L1) +T(L2) +T(L3-L7) =O(1) +O(1) +O(n).
Volvemos a aplicar nuestra vieja conocida, la propiedad d de la suma, y llegamos al si-
guiente resultado final:
T(alg) =T(L1) +T(L2) +T(L3-L7) =O(1) +O(1) +O(n) =O(n).
Eureka!
FUOC P01/75001/00075 42 Tipos abstractos de datos
4.2. Eficiencia espacial
Podemos aplicar las misma ideas y metodologa que en los subapartados ante-
riores para asignar una categora al espacio ocupado por una representacin
de TAD y poder comparar alternativas para un mismo TAD. En este caso, uti-
lizaremos las siguientes reglas:
1) Un atributo o posicin de un vector de tipo predefinido consume un espa-
cio O(1). Tambin tiene coste O(1) cualquier referencia a un objeto.
2) Un vector de n posiciones ocupa el producto de n por el espacio de cada
posicin:
E(vector [1..n] de t) = n E(t).
3) Una tupla de n componentes ocupa la suma de los espacios de los compo-
nentes:
E(tupla v
1
: t
1
; ...; v
n
: t
n
ftupla) = k: 1 k n: E(t
k
)
4) El espacio de la implementacin de un TAD es igual a la suma del espacio
requerido por sus atributos:
E(atributo v
1
: t
1
, ..., v
n
: t
n
) = k: 1 k n: E(t
k
)
Ejemplo de clculo de la eficiencia espacial
Sea la siguiente representacin del tipo misterioso:
Entonces, por la regla 4:
E(misterioso) =E(Nat) + E(Nat) + E(vector[1n] de ) =
= O(1) + O(1) +E(vector[1n] de ) =
Por la regla 2:
=O(1) +O(1) +n + E(tupla) =
Aplicamos la regla 3:
=O(1) +O(1) +n (E(Entero) +E(Nat)) =
La funcin de eficiencia espacial E(x) denota el espacio ocupado por
la representacin de tipo x medido con la notacin O.
atributos prim, sl: Nat
A: vector [1n] de
tupla
x: Entero
enc: Nat
ftupla
Las propiedades de la notacin O
tambin son aplicables en este
contexto.
FUOC P01/75001/00075 43 Tipos abstractos de datos
Aplicamos la regla 1:
=O(1) +O(1) +n + (O(1) +O(1)) =
Entonces las propiedades c y d de la notacin O
=O(1) +n O(1) =O(1) +O(n) =O(n).
En el caso de la medida del espacio, a veces preferimos contar exactamente el
espacio en trminos de cantidad de espacio de memoria ocupado (dada una
unidad fijada) y no calcular el espacio asinttico. Esto se debe al hecho de que,
muy a menudo, las alternativas tendrn un comportamiento asinttico idn-
tico y se tendr que llevar a cabo un estudio ms cuidadoso para compararlas.
Ejemplo de clculo de espacio ocupado por una representacin de tipos
En el caso del ejemplo de antes, obtenemos:
E
0
(misterioso) = E
0
(Nat) + E
0
(Nat) + E
0
(vector[1..n] de...) =
= 2E
0
(Nat) + n (E
0
(Entero) + E
0
(Nat)) =
= (n + 2) E
0
(Nat) + n E
0
(Entero)
Dando valores concretos (en nmero de bytes) a E
0
(Nat) y E
0
(Entero), obtendramos un
nmero de bytes concreto.
Otra situacin en la que nos puede interesar determinar (asinttica o exacta-
mente) el espacio ocupado ser el estudio del espacio auxiliar (variables lo-
cales) utilizado por el algoritmo. Este estudio complementar el de eficiencia
temporal de las alternativas para elegir una que nos convenga en un contexto
de uso determinado.
La funcin E
0
(x) denota el espacio ocupado por la representacin de
tipo x medido exactamente en mltiplos de una unidad dada (tpica-
mente, bytes).
FUOC P01/75001/00075 44 Tipos abstractos de datos
5. Representacin de contenedores usando vectores
Como ya hemos comentado, el punto clave por lo que se refiere a las implemen-
taciones de los TAD de los contenedores es la estrategia de almacenamiento de
sus elementos, y ste es el objeto de estudio de este apartado. Nos centraremos
aqu en las estrategias que guardan los elementos en un vector, y dejamos para
el siguiente apartado las estrategias que usan la llamada memoria dinmica.
Ilustraremos los diferentes conceptos mediante la implementacin de un TAD
residente en la jerarqua. El TAD de los sacos permite usar en los programas el
concepto deconjunto con repeticiones, es decir, conjuntos en los que los elemen-
tos pueden aparecer ms de una vez. Consideramos el TAD de los sacos acota-
dos dado que usamos vectores para almacenar los elementos y stos tienen
una capacidad limitada. Si bien ya hemos comentado la existencia en Java de
una clase Vector que permite que el vector pueda crecer dinmicamente si lo
necesita, aqu preferimos centrarnos en el constructor de tipo habitual que en-
contramos en la mayora de los lenguajes de programacin.
La interfaz del TAD de los sacos acotados se muestra completa en la siguiente figura:
5.1. Representacin secuencial
El objetivo de este subapartado es ilustrar una de las representaciones de TAD
ms habituales.
5.1.1. Presentacin
Seguramente, la forma ms simple de representar un contenedor consiste en al-
macenar todos sus elementos en un vector, agruparlos en uno de los extremos
(por convencin, el extremo izquierdo, es decir, las posiciones con un ndice
Consultad el TAD de los sacos en el
subapartado 2.2.3. de este mdulo
didctico.
FUOC P01/75001/00075 45 Tipos abstractos de datos
menor, aunque esta decisin es irrelevante), aadiendo un valor natural que
delimita la parte ocupada y la parte libre del vector, llamado apuntador de si-
tio libre (si apunta a la primera posicin libre) o apuntador al ltimo (si
apunta a la ltima posicin ocupada). Es la llamada estrategia de representa-
cin secuencial.
La siguiente figura muestra el estado de un vector con apuntador de sitio libre
que almacena n elementos v
1
, , v
n
:
Si bien los detalles de implementacin pueden cambiar de una implementa-
cin concreta a otra, hay determinados hechos que estn en todas:
1) Son simples y dan lugar a invariantes de representacin y cdigo de las
operaciones fcilmente comprensibles.
2) Desde el punto de vista del espacio, las representaciones secuenciales son
ptimas si conocemos el nmero de elementos que se tienen que almacenar
en el contenedor, porque slo se necesita el espacio para stos y algn apun-
tador adicional, de coste prescindible.
3) La consulta de los elementos tiene un coste lineal sobre la dimensin del
vector, dado que hay que aplicar el tpico esquema de bsqueda, a no ser que
los elementos estn ordenados, aplicndose el algoritmo de bsqueda dicot-
mica, de coste logartmico.
4) La insercin es ms o menos costosa dependiendo de si hay que controlar
la existencia previa del elemento que se tiene que insertar. Si no hace falta, el
coste es O(1). Si hace falta, aumenta hasta coste lineal a causa de la bsqueda.
5) La supresin es de coste lineal a causa de la bsqueda. Una vez localizado
el elemento que se tiene que borrar en la posicin x del vector, se tiene que
mover el elemento que ocupa la ltima posicin a la posicin x, para asegurar
la continuidad total de los elementos en la tabla.
Pese a su sencillez, esta estrategia de representacin se puede aplicar a una gran
variedad de TAD, y puede ser til en determinadas circunstancias, especialmente
Cualquier implementacin basada en el almacenamiento consecutivo
de los elementos de una estructura en un vector se denomina represen-
tacin secuencial.
Apuntadores o cursores
Los naturales que apuntan a
posiciones de vector se llaman
en general apuntadores.
Tambin hay autores que los
llaman cursores.
Consultad el esquema de bsqueda
tpico introducido en la asignatura
Fundamentosde programacin I.
FUOC P01/75001/00075 46 Tipos abstractos de datos
cuando los requisitos de eficiencia no son demasiado elevados o cuando el volu-
men de datos que se tiene que manejar es reducido.
5.1.2. Una primera representacin secuencial
Disponemos los elementos de los sacos en posiciones consecutivas de un vector,
empezando por la primera, siguiendo la estrategia secuencial. Adems, habr un
contador de elementos, que en realidad es el mismo atributo tamao que se he-
reda de Contenedor. Sin embargo, hay que tomar una primera decisin: consu-
me cada aparicin de un mismo elemento una posicin del vector? La estrategia
es factible, y puede ser til en determinados contextos. Sigmosla, pues.
Declaramos el atributo A (el vector), que se aade a los atributos heredados. Re-
servamos una posicin adicional para usar la tcnica del centinela en las bs-
quedas exigidas por la supresin y la consulta de existencia. El invariante de la
representacin tiene que establecer que el tamao no supere el valor mximo.
Por lo que se refiere a la implementacin de las operaciones, la creacin y la
insercin tienen un comportamiento sencillo. Cuando se suprime un elemen-
to, hay que buscar la primera aparicin (dado que todos son equivalentes).
Puesto que en el caso general esta aparicin se situar en el medio, copiaremos
el ltimo elemento de la parte ocupada del vector. Por ltimo, para saber el n-
mero de apariciones de un elemento, hay que recorrer el vector e ir contando.
A continuacin se presenta la implementacin entera:
clase SacoAcotadoSecuencialConRepeticiones implementa SacoAcotado
atributos
protegidos
mximo, tamao: Nat
privado
A: vector [1mximo +1] de Elem
invariante tamao mximo
operaciones
mtodo crea(n: Nat)
mximo :=n; tamao :=0
mtodo nbElems() : Nat
retorna tamao
mtodo vacio? (): Bool
retorna (tamao =0)
mtodo lleno?(): Bool
retorna (tamao =mximo)
mtodo inserta(v: Elem)
precondicin tamao <mximo
tamao :=tamao +1; A[tamao] :=v
mtodo borra (v: Elem)
k: Nat
k : = 1; A[tamao +1] : = v
Hiptesis
Aqu supondremos que el atri-
buto A se crea implcitamente
en el mtodo crea. Este hecho
depender en ltimo trmino
del lenguaje de programacin
utilizado.
FUOC P01/75001/00075 47 Tipos abstractos de datos
El estudio de la eficiencia se ofrece a continuacin. Los rasgos ms relevantes son:
1) Recordamos que la asignacin entre valores de tipo predefinidos es siempre
O(1), mientras que el coste de la asignacin y comparacin entre elementos es
T(E(Elem)).
2) Recordemos que el coste de la composicin secuencial de asignaciones que
tiene coste O(1) es tambin O(1), como sucede por ejemplo en crea.
3) Como parece razonable, suponemos en el clculo de los costes que se cum-
plemximo >>E(Elem), y por la propiedadd de simplificacin de la notacin O:
O(mximo) +O(E(Elem)) =O(mximo).
4) Observamos que, por mucho que el atributo tamao da la cota superior de
los bucles, en realidad calcula el peor de los casos, y este caso se produce cuan-
do la estructura est llena, es decir, cuando tamao =mximo.
Entonces, con todo esto obtenemos:
crea: O(1) +O(1) +O(mximo n) =O(mximo n). Fijmonos en que he-
mos tenido en cuenta el coste de creacin del atributo vector.
nbElems, vacio?, lleno?: O(1).
inserta: O(1) + O(n) = O(n).
mientras A[k] <>v hacer k :=k +1 fmientras
si k <>tamao +1 entonces
A[k] :=A[tamao]; tamao :=tamao 1
fsi
mtodo existe(v: Elem): Bool
k: Nat
k :=1; A[tamao +1] :=v
mientras A[k] <>v hacer k :=k +1 fmientras
retorna k tamao
mtodo nAps(v: Elem): Nat
k, cuantos: Nat
cuantos :=0
por K :=1 hasta tamao hacer
si A[k] =v entonces cuantos :=cuantos +1 fsi
fpor
retorna cuantos
fin clase
Asignacin y comparacin
en lenguajes OO
Si bien ya hemos comentado
que en la mayora de los
lenguajes orientados a objetos
la asignacin y la comparacin
no involucran los objetos sino
slo las referencias, preferimos
movernos dentro del caso ms
general posible. En el apartado
6 hablaremos ms de objetos
y referencias.
n denota el coste de E(Elem).
FUOC P01/75001/00075 48 Tipos abstractos de datos
borra: O(1) + O(n) + (mximo (O(n) + O(1)) + (O(1) +O(n) + O(1)) =
= O(1) + O(n) + O(mximo) O(n) + O(n) = O(mximo) O(n) = O(mximo n).
existe: O(1) + O(n) + (mximo (O(n) + O(1)) + O(1) = O(mximo n).
nAps:O(1) + (mximo (O(1) + (O(n) + O(1))) + O(1) =O(mximo n).
En cuanto al clculo del coste, obtenemos lo siguiente:
a) Por lo que respecta al coste espacial, asintticamente es:
E(Sac) = (mximo + 1) O(n) + O(1) + O(1) = O(mximo n).
como era de esperar.
b) Si nos centramos en el coste espacial real:
E
0
(SacoAcotadoSecuencialConRepeticiones) =
= (mximo+ 1) E
0
(Elem) + 2E
0
(Nat).
5.1.3. Una segunda representacin secuencial
El mayor problema de esta representacin tiene que ver con la eficiencia de las
operaciones estudiadas. Una alternativa consiste en incluir en las posiciones
del vector un contador del nmero de apariciones de cada elemento. Adems,
necesitamos aadir un nuevo atributo ltimo para conocer el nmero de posi-
ciones ocupadas realmente, diferente del valor de tamao, que siempre indica
el nmero de elementos del contenedor, y obtenemos:
Estas modificaciones influyen en el invariante de la representacin, que estable-
ce la relacin entre los contadores individuales, que tienen que ser diferentes de
atributos
protegidos
mximo; tamao: Nat
privado
A: vector [1mximo +1] de
tupla
v: Elem
cont: Nat
ftupla
ltimo: Nat
FUOC P01/75001/00075 49 Tipos abstractos de datos
cero (segunda lnea), y el contador total mediante un sumatorio (tercera lnea),
y asegura que los elementos no aparecen ms de una vez (cuarta lnea):
Es decir, el resultado es ms complicado que antes, pero esto no nos debe ex-
traar porque la estructura es ms compleja.
Por lo que respecta a las operaciones, se adaptan de forma simple a la situa-
cin, y por este motivo no se muestran. Slo mencionamos la conveniencia
de introducir un mtodo-funcin privado bsqueda para localizar la posicin
donde se encuentra un elemento, que retorna ltimo+ 1 si no lo encuentra. El
resto de las operaciones usarn frecuentemente este mtodo.
Si analizamos el resultado, nos llevamos una sorpresa (o no?): el comportamien-
to asinttico en el peor de los casos no mejora en ninguna operacin, ni siquiera
en el caso denAps, porque si bien no es necesario examinar toda la parte ocupada
del vector, s que hay que buscar el elemento involucrado en la operacin, y en
el peor de los casos, este coste es el mismo.
Es ms, la operacin de insercin empeora su comportamiento porque ahora
hay que buscar el elemento insertado dentro del vector por si ya existe, de
modo que la funcin se convierte en lineal sobre el mximo de elementos,
T(inserta) =O(mximo E(Elem)).
Entonces, cundo es til esta representacin? Slo en el caso de que el par-
metro n de la creacin represente no el nmero mximo total de elementos,
sino el nmero mximo de elementos diferentes. En este caso, la primera im-
plementacin es inviable, o se tendr que sobredimensionar en exceso la es-
tructura. De otro modo, el aparente beneficio de eficiencia, consecuencia de
aadir los contadores, en realidad no es tal.
5.1.4. Representaciones secuenciales marcadas
El movimiento de elementos exigido por las actualizaciones en la representa-
cin secuencial provoca una situacin que puede ser inconveniente cuando se
realizan implementaciones de TAD complejos.
Cuando es preciso acoplar dos estructuras diferentes para alcanzar las funcio-
nalidades pedidas, es frecuente que los elementos de estas estructuras estn
Invariante
ltimo mximo
k: 1 k ltimo: (A[k].cont > 0)
tamao = (k: 1 k ltimo: A[k].cont)
j, k: 1 j < k ltimo: (A[j].v A[k].v)
El peor caso
El peor de los casos es que la
estructura est llena y el ele-
mento que buscamos sea
el ltimo; si adems todos los
elementos aparecen una sola
vez, incluso el coste no asint-
tico es el mismo.
Obviamente, si cambia
el significado de la creacin,
en realidad hablamos de un TAD
diferente.
Podis ver varios ejemplos
de acoplamiento de estructuras en
el mdulo Diseo de estructuras
de datosde esta asignatura.
FUOC P01/75001/00075 50 Tipos abstractos de datos
relacionados. Esta relacin puede dar lugar al hecho de que todo elemento A
de una de las estructuras incluya un valor natural que identifique la posicin
que ocupa en el vector el elemento B de la otra estructura con la que se rela-
ciona. Si B cambia de lugar porque la estructura correspondiente est represen-
tada secuencialmente, es necesario modificar el valor del natural que tiene A,
y esto puede resultar costoso.
Si se quieren evitar estos movimientos, una solucin consiste en marcar las po-
siciones del vector que conforman la parte ocupada pero que no contienen in-
formacin relevante a causa de las supresiones.
La siguiente figura muestra grficamente las marcas en un vector (las posicio-
nes marcadas tienen un cuadrado sombreado; los valores que aparecen son
irrelevantes):
Entonces, la supresin no efecta ningn movimiento, sino que la marca de la
posicin que contiene el elemento que se debe borrar se activa; se dice que la po-
sicin se marca, de modo que a partir de este momento la posicin pasa a estar
marcada.
Esta estrategia impacta en el comportamiento de la insercin, que tiene que
considerar las posiciones marcadas segn una de las dos polticas siguientes:
a) Las inserciones siguen el esquema simple anterior, pero cuando se agota la
parte libre se reorganiza el vector para eliminar las posiciones marcadas y vol-
ver a la situacin ideal, sin marcas. Sin embargo, fijaos en que entonces las
marcas pierden su funcin primordial: evitar movimientos de elementos en la
estructura.
Una marca es un indicador del estado de la posicin del vector. Puede
indicar libre u ocupada.
Acoplamiento
de estructuras
Muchas veces, en el marco de
la orientacin a objetos, el
acoplamiento de estructuras
se hara incluyendo en Ano un
apuntador en una posicin de
B, sino una referencia al objeto
almacenado en la posicin de
B, y entonces, en realidad, el
movimiento no afectara a A,
de forma que este problema
no se dara.
Un cambio de la posicin de B
requiere la actualizacin de A.
Un cambio de la posicin de B
requiere la actualizacin de A.
En este vector
los elementos v
1
, v
3
, v
5
, v
6
estuvieron dentro de la estruc-
tura en algn momento del
pasado, pero se han borrado
y ya no estn.
FUOC P01/75001/00075 51 Tipos abstractos de datos
b) En cada insercin hay que buscar la primera posicin marcada del vector y
ocuparla con el nuevo elemento. Se dice que la posicin se recicla.
Fijmonos en que tambin la bsqueda sufre por la existencia de las marcas,
porque durante la bsqueda se pasa por las posiciones marcadas, pese a que se
sabe seguro que no pueden contener el elemento buscado. Eso s, el incremen-
to de coste no es asinttico.
Las marcas se pueden implementar sin desperdiciar espacio siempre que haya
algn elemento del dominio de los elementos que podamos usar con este pro-
psito. Si no, hay que aadir a las posiciones un campo booleano con el con-
secuente incremento (no asinttico) del espacio de la representacin.
Actividad
2. Aadid marcas a la implementacin de los sacos que habis visto en este apartado.
5.1.5. Representaciones secuenciales ordenadas
Las estrategias secuenciales que hemos visto penalizan tanto las operaciones de
actualizacin del contenedor como las de consulta individual de los elementos.
Si bien la primera situacin en ocasiones resulta aceptable, el mal comporta-
miento de las consultas puede ser muy decisivo para descartarlas.
Larepresentacin ordenada se caracteriza por los siguientes hechos:
1) Los elementos forman un dominio ordenado.
2) No exige ningn atributo nuevo, pero s aade una restriccin en el inva-
riante de la representacin, para asegurar que los elementos realmente apare-
cen en orden.
3) Las operaciones de insercin y supresin siempre son lineales, y adems re-
quieren mover elementos para mantener el vector ordenado. Estos movimien-
tos pueden comportar los problemas mencionados en el subapartado anterior.
4) La operacin de consulta se implementa sobre la versin de los sacos, de
forma que el coste resultante deja de ser lineal y pasa a ser logartmico, que es
muy aceptable.
Aplicamos esta estrategia sobre la versin de los sacos con contadores en las posi-
ciones para evitar repeticiones. Por lo que se refiere a la representacin, los atribu-
tos no cambian, pero s lo hace la invariante de la representacin, que establece
La representacin secuencial ordenada es una variante de estrategia
secuencial que optimiza las consultas.
FUOC P01/75001/00075 52 Tipos abstractos de datos
la ordenacin de los elementos; es suficiente con modificar ligeramente la cuarta
frmula del predicado, cambiando la desigualdad por una comparacin:
El impacto de este pequeo cambio en el invariante es enorme. Los hechos
ms importantes son: todo cambio en la configuracin del vector obliga a mo-
ver elementos para asegurar tanto su continuidad (exigida por la calidad de se-
cuencialidad) como su ordenacin. Sin embargo, dado que las dos operaciones
afectadas (insercin y supresin) ya eran O(mximo E(Elem)), el coste asint-
tico no se ve afectado.
En cambio, las operaciones consultoras sobre los elementos (existey nAps) se
pueden beneficiar de la ordenacin para hacer bsquedas dicotmicas en lu-
gar de bsquedas lineales, con el beneficio de eficiencia asociado.
Finalmente, la eficiencia temporal resulta de esta manera:
nbElems, vacio?, lleno?: O(1).
crea, inserta, borra: O(mximo n). Detalladamente:
O(log(mximo n)): bsqueda dicotmica del elemento.
O(1): comprobaciones.
O(1): incremento/decremento de contador.
O(mximo n): desplazamiento de elementos.
En total: O(mximo n).
existe, nAps: O(log(mximo n)), por la bsqueda dicotmica.
Por lo que se refiere al coste espacial, asintticamente no hay ningn cambio;
as, se obtiene O(mximo E(Elem)). El coste real es idntico al caso anterior.
Es decir, disponemos de una representacin secuencial de caractersticas dife-
rentes a las anteriores que reduce sensiblemente el coste de las operaciones de
consulta de elementos. El precio que se tiene que pagar es nulo (desde el punto
de vista asinttico) con respecto a la representacin secuencial del subaparta-
do 5.1.3., e incrementa el coste de la insercin con respecto a la representacin
secuencial del subapartado 5.1.2. Dependiendo de los requisitos de utilizacin
del TAD, se puede optar por una representacin u otra.
invariante
ltimo ltimo
k: 1 k ltimo: (A[k].cont > 0)
tamao = (k: 1 k ltimo: A[k].cont)
j, k: 1 j < k ltimo: (A[j].v < A[k].v)
Un cambio de la posicin de B
requiere la actualizacin de A.
Utilizamos el smbolo < en vez
del mtodo menor por motivos
de legibilidad.
Abreviamos E( Elem) por n.
El coste logartmico de la bsqueda
dicotmica se calcula en al asignatura
Fundamentos de programacin I.
Observad que
la bsqueda dicotmica no
reduce el coste de las insercio-
nes y las supresiones, pero
permite reutilizar el cdigo.
Consultad las estrategias bsicas de
representacin introducidas en el
apartado 3 de este mdulo didctico.
FUOC P01/75001/00075 53 Tipos abstractos de datos
5.2. Representaciones encadenadas
Si bien en determinados contextos las representaciones secuenciales que hemos
visto hasta ahora son muy satisfactorias, en el caso general presentan algunos
inconvenientes que desaconsejan su adopcin, inconvenientes derivados del
hecho de que cualquier modificacin de la estructura que implique insertar un
elemento nuevo por el medio de la parte ocupada o borrar un elemento cual-
quiera provoca el movimiento de varios elementos, para asegurar que se sigue
cumpliendo la propiedad de representacin secuencial. El movimiento de ele-
mentos tiene tres inconvenientes principales:
1) El coste de los movimientos individuales en s. A veces, este coste es prescin-
dible en el contexto del anlisis asinttico de los programas que hemos adopta-
do para medir la eficiencia, aunque no siempre ser as. Adems, puesto que
habitualmente definimos los TAD genricos, en los que se desconoce por ade-
lantado el tipo de elementos que se almacenan, entonces se puede desconocer
tambin su dimensin.
2) La prdida del acoplamiento con otras estructuras. Ya hemos comentado
en el subapartado anterior que en determinadas circunstancias, los movimien-
tos pueden desajustar estructuras que estn acopladas.
3) El nmero de movimientos. Este parmetro realmente es relevante en el
anlisis asinttico del comportamiento de las operaciones. A menudo, el n-
mero de movimientos es lineal con respecto al nmero de elementos de la es-
tructura, y esta linealidad es normalmente inaceptable.
Para solucionar estos problemas se introducen las representaciones encadenadas.
Esto significa que en el vector no habr zonas diferenciadas ocupadas o libres,
sino que cualquier posicin puede estar ocupada por un elemento o libre, inde-
pendientemente del estado de las posiciones ms prximas; es ms, por un mis-
mo valor del TAD habr muchas configuraciones del vector que lo implementen.
La pregunta que se plantea es: cmo se sabe qu posiciones del vector contienen
informacin relevante? Ya conocemos la estrategia de marcaje de posiciones,
con los inconvenientes que comporta. Una alternativa consiste en introducir un
campo adicional en cada posicin de tipo entero, de forma que una posicin
ocupada lleva a otra siguiendo el valor de este campo. El campo entero recibe el
nombre de encadenamiento (o enlace), y tambin decimos que el encadena-
miento apunta a una posicin del vector.
Lasestrategias de representacin encadenadas (tambin llamadas es-
trategias enlazadas) tienen como objetivo evitar los movimientos de
elementos en la estructura cada vez que se borra o se inserta uno.
Ejemplo de coste
prescindible
Si un elemento es un entero, o
un entero y un booleano; o en
el caso de los lenguajes orienta-
dos a objetos, cuando en reali-
dad los elementos siempre son
direcciones; en todos estos ca-
sos, el coste de los movimientos
individuales es prescindible en
trminos de anlisis asinttico.
Estado de una posicin
El estado de una posicin
depender de la estrategia de
codificacin de las operaciones
del TAD, as como de la historia
de inserciones y supresiones de
la estructura. Esto hace que la
posicin que ocupa un
elemento dentro del vector no
tenga ningn significado.
FUOC P01/75001/00075 54 Tipos abstractos de datos
As pues, la representacin encadenada parece una opcin recomendable, so-
bre todo con estructuras voltiles que tengan un coste lineal al insertar o bo-
rrar, o bien cuando los elementos de la lista presentan unas dimensiones lo
bastante grandes para que el espacio de los encadenamientos sea prescindible,
o bien cuando el contexto de uso no imponga requerimientos de eficiencia es-
pacial demasiado estrictos.
La siguiente figura muestra dos configuraciones equivalentes de un vector con
representacin encadenada. Los encadenamientos se muestran de forma gr-
fica, con una flecha hacia la posicin apuntada. Cada elemento apunta a otro;
hay un apuntador en el primer elemento. Para identificar el final, hacemos
que el ltimo elemento tenga un encadenamiento nulo, que representamos con
una lnea acabada en un crculo. El valor del encadenamiento nulo ser tal que
no identifique ninguna posicin vlida del vector; por convencin, siempre le
daremos el valor mximo del vector ms 1.
An hay una cuestin por resolver: la gestin del espacio libre del vector. Es
decir, cada vez que se inserte un elemento hay que obtener una posicin del
vector donde almacenarlo y, al borrarlo, hay que recuperar esta posicin para
reutilizarla.
Una primera solucin consiste en marcar las posiciones del vector como ocu-
padas o libres y tomar espacio del final del vector hasta que se agote, y en-
tonces reorganizar el vector; precisamente, el problema de este esquema lo
suponen las reorganizaciones. Alternativamente, los sitios libres se pueden
encadenar de forma que se obtengan rpido posiciones y se liberen; puesto
que no importa la posicin elegida, el espacio libre se organiza de la forma
ms sencilla posible, mediante una gestin llamada pila de sitios libres, apro-
vechando el mismo campo de encadenamiento para enlazar los elementos y
as no tener que desperdiciar espacio.
Resumiendo, el precio que se tiene que pagar para ahorrar movimientos
de elementos es simplemente aadir un campo entero a cada posicin
del vector.
Representaciones
encadenadas...
... y modelos recursivos. Las
representaciones encadenadas
encajan de forma natural en la
representacin de TAD que se
definen sobre un modelo recur-
sivo, como es el caso de las se-
cuencias y de los rboles que se
ven en el mdulo Secuencias
y rboles.
Un cambio de la posicin de B
requiere la actualizacin de A.
Los dos vectores contienen
los mismos elementos
en el mismo orden.
El concepto de pila se estudia en el
mdulo Secuencias y rboles.
FUOC P01/75001/00075 55 Tipos abstractos de datos
Con esta gestin, cuando se inserta un elemento se deposita en la ltima posi-
cin liberada por una supresin. Inicialmente, todas las posiciones del vector
formarn la pila de sitios libres; haremos que toda posicin apunte a la siguien-
te, excepto la ltima, y tendremos el apuntador de sitio libre en la primera po-
sicin del vector.
La siguiente figura muestra el mismo vector que la figura anterior, pero aade
la gestin de sitios libres. Adems, sustituimos el apuntador al primer elemen-
to por una posicin adicional del vector, la posicin 0, que en realidad no es
ms que un elemento fantasma. El elemento fantasma es un elemento que se
deposita cuando se crea la estructura encadenada y que no contiene informa-
cin relevante; su existencia simplifica los algoritmos de manipulacin del ti-
po, especialmente la supresin.
Sin embargo, normalmente, las representaciones encadenadas se muestran ms
esquemticas, y slo se centran en los elementos y no tanto en la configuracin
exacta del vector. Podemos mostrar el ejemplo anterior de la siguiente forma:
Por lo que se refiere a la codificacin de las operaciones, crea se limita a crear
la pila de sitios libres y depositar el fantasma. La operacin de aadir obtiene
una posicin de la pila de sitios libres e inserta el elemento. La operacin de
supresin busca la primera aparicin del elemento y, si lo encuentra, libera la
posicin y la inserta en la pila de sitios libres. Aparte de estas dos, tambin
mostramos el mtodo-funcin nAps.
Actividad
3. Codificad el resto de las operaciones asociadas a las representaciones encadenadas.
A partir de esta idea bsica, se pueden aplicar las variantes ya vistas, especial-
mente por lo que se refiere a la ordenacin de los elementos dentro de la estruc-
tura. Sin embargo, como ya se ha indicado, la ordenacin en una estructura
encadenada no sirve para mejorar el coste asinttico medido por la O-grande;
slo mejora el caso intermedio, que no tratamos aqu.
El fantasma
y el apuntador
A partir del fantasma, encon-
tramos todos los elementos
guardados en la estructura.
A partir del apuntador, encon-
tramos todas las posiciones
libres del vector.
Tambin se puede dejar
de mostrar el fantasma.
FUOC P01/75001/00075 56 Tipos abstractos de datos
clase SacoAcotadoEncadenado implementa SacoAcotado
clase Nodo
atributos pblicos v: Elem; enc: Nat
fin clase
atributos
protegidos mximo, tamao: Nat
privados sl: Nat; A: vector [0..mximo] de Nodo
invariante sl mximo +1 tamao =||cadena(0)|| 1
cadena (0) cadena (sl) ={mximo +1}
cadena (0) cadena (sl) =[0, mximo +1]
donde cadena(mximo +1) ={mximo +1}
n <mximo +1 cadena(n) ={n} cadena(A[n].enc)
operaciones
mtodo crea(n: Nat)
i: Nat
mximo :=n
por i :=1 hasta mximo hacer A[i].enc :=i +1 fpor
sl :=1; A[0].enc :=mximo +1; tamao :=0
mtodo aade(v: Elem)
precondicin tamao <mximo
tiempo: Nat
tiempo :=A[sl].enc; A[sl].v :=v; A[sl].enc :=A[0].enc
A[0].enc :=sl; sl :=tiemp
tamao :=tamao +1
mtodo borra(v: Elem)
ant, act: Nat; encontrado: Booleano
ant :=0; act :=A [0].enc; encontrado :=falso
mientras act <>mximo +1 encontrado hacer
si A[act].v =v entonces encontrado :=cierto
sino ant :=act :=A[act].enc
fsi
fmientras
si encontrado entonces
A[ant].enc :=A[act].enc; A[act].enc :=sl; sl :=act
tamao :=tamao 1
fsi
mtodo nAps(v: Elem): Nat
k, cuantos: Nat
k :=A[0].enc; cuantos :=0
mientras k <>mximo +1 hacer
si A[k] =v entonces cuantos :=cuantos +1 fsi
k :=A[k].enc
fmientras
retorna cuantos
fin clase
Observad la necesidad de definir
una clase auxiliar para los
elementos del vector.
Clase
SacoAcotadoEncadenado
En la primera lnea del invarian-
te se dan los valores permitidos
parasl y se establece el valor
del contador; en la segunda y
tercera lneas se establece que
toda posicin del vector forma
parte o bien slo de la lista de
elementos, o bien slo de la
pila de sitios libres.
Recordad que mximo + 1
representa el encadenamiento
nulo. La funcin cadena retor-
na el conjunto de posiciones
que cuelgan a partir de una
posicin dada.
Al borrar
necesitamos el apuntador
en el elemento anterior al ac-
tual durante la bsqueda para
poder actualizar correctamen-
te los encadenamientos.
FUOC P01/75001/00075 57 Tipos abstractos de datos
5.2.1. Algunas variantes de representaciones encadenadas
En diferentes contextos encontraremos la necesidad de adaptar los conceptos ge-
nerales aqu vistos. En este subapartado introduciremos dos variantes habituales:
las representaciones encadenadas circulares y las doblemente encadenadas.
La necesidad de esta estrategia surge en varias situaciones; destacamos las si-
guientes:
Desde cualquier elemento se puede acceder a cualquier otro. Esto es es-
pecialmente interesante cuando se puede acceder a cualquier elemento
de forma directa (mediante apuntadores externos) y hay que localizar al-
gn elemento que contiene informacin especial, o bien recorrer la es-
tructura entera.
Cuando en una representacin hay que distinguir el primero y el ltimo
elemento, es suficiente con un apuntador en el ltimo.
As pues, en las representaciones doblemente encadenadas tenemos un gasto
de espacio adicional, al contrario que en el caso de la variante anterior. Su uti-
lidad radica en los siguientes aspectos:
Permite recorrer la estructura en dos sentidos diferentes.
Cuando los elementos se pueden suprimir directamente mediante apunta-
dores, los encadenamientos dobles son la nica forma de implementar la
supresin en tiempo constante.
Tanto las representaciones circulares como las doblemente encadenadas acos-
tumbran a tener elemento fantasma para simplificar los algoritmos. En el caso
doblemente encadenado, adems, se acostumbran a cerrar circularmente las
Las representaciones encadenadas circulares se caracterizan por enla-
zar el ltimo elemento con el primero, tal como se muestra en el siguien-
te dibujo:
En lasrepresentaciones doblemente encadenadas, cada elemento apun-
ta no slo al siguiente, sino tambin al anterior.
La segunda situacin
se da con frecuencia cuando
se acoplan estructuras de
datos, como hemos mostrado
en el subapartado 5.1.4.
de este mdulo didctico.
FUOC P01/75001/00075 58 Tipos abstractos de datos
dos estructuras encadenadas subyacentes, tambin por razones de simplicidad
en la programacin:
5.3. Tabla comparativa de las implementaciones vistas
El ejemplo de implementacin de los sacos, pese a su simplicidad, nos ha permi-
tido ilustrar las estrategias bsicas de representacin que ya hemos introducido, a
la espera de otras polticas ms sofisticadas que veremos a lo largo de la asignatura.
La tabla siguiente nos proporciona una visin panormica de las soluciones
que hemos visto.
La confeccin de una tabla como sta es una ayuda inestimable en el momento
de decidir cul es la mejor implementacin de un TAD en un contexto determi-
nado. Por eso, es muy recomendable que forme parte de la documentacin de
las implementaciones de los TAD.
En la tabla hay que destacar los siguientes hechos:
Aunque siempre se utiliza el mismo smbolo para representar el mximo
nmero de elementos, ya hemos comentado que en el caso de representa-
ciones con contador de apariciones en las posiciones de este mximo ser
seguramente menor.
Hemos aadido una columna para consignar si se producen movimientos
de elementos o no, dada la importancia potencial de este factor.
Hemos considerado que la asignacin y la comparacin de elementos tie-
nen el mismo coste.
En la representacin marcada, hemos representado la marca con un campo
booleano.
Hemos aadido una fila para las representaciones encadenadas ordenadas,
para el caso de contador de apariciones en las posiciones.
Estrategia T( crea) T( aade) T( borra) T( nAps) E
0
( Saco) Movimientos
5.1.2 m n n m n m n (m+ 1) n
0
+ 2k S
5.1.3 m n m n m n m n (m+ 1) (n
0
+ k) + 3k S
5.1.4 m n m n m n m n (m+ 1) (n
0
+ b) + 2k No
5.1.5 m n m n m n log(m) n (m+ 1) (n
0
+ k) + 3k S
5.2 m n n m n m n (m+ 1) (n
0
+ k) + 3k No
5.2 orden. m n m n m n m n (m+ 1) (n
0
+ k) + 3k No
Notacin
Utilizamos las siguientes
abreviaturas:
m como mximo;
n como E(Elem);
n
0
como E
0
(Elem);
k como E
0
(Nat);
b como E
0
(Bool).
FUOC P01/75001/00075 59 Tipos abstractos de datos
6. Implementacin de TAD con una memoria dinmica
Las representaciones que habis visto hasta ahora se basan en el uso de vecto-
res para almacenar los elementos. En la mayora de los lenguajes de programa-
cin actuales, los vectores presentan tres caractersticas que en ocasiones (no
siempre) resultan inconvenientes:
1) Hay que determinar su dimensin en algn momento. Dependiendo del
lenguaje, la dimensin se fija en tiempo de compilacin o de ejecucin.
2) El espacio ocupado por la estructura es fijo, independientemente del n-
mero de elementos que se encuentren en cada momento. Dicho con otras pa-
labras, todas las posiciones libres del vector estn desaprovechadas. Si tenemos
dos estructuras gestionadas con vectores, una muy vaca y otra totalmente lle-
na, las inserciones en la segunda daran error porque no se podra usar el es-
pacio desaprovechado de la primera.
3) La dimensin del vector acta como una cota del nmero de elementos
que caben en el mismo, de forma que los TAD son finitos.
Estos inconvenientes pueden no ser tan graves si el lenguaje de programacin
utilizado permite crear e incluso redimensionar los vectores en tiempo de eje-
cucin.
Para solucionar estos problemas, presentamos la nocin de memoria dinmica,
presente de una forma u otra en todos los lenguajes de programacin impera-
tivos y orientados a objetos actuales.
Es decir, durante la ejecucin, el programa puede ir depositando datos en la
memoria dinmica, a medida que estos datos se crean y aumentan. Cuando ya
no son necesarios, el espacio usado para almacenarlos queda libre y se puede
utilizar en otras estructuras del mismo programa.
Es importante destacar que la memoria dinmica en general se usa para imple-
mentar los TAD no acotados que aparecen en la jerarqua de clases.
Como ya hemos dicho, la memoria dinmica existe en todos los lenguajes
de programacin comerciales. Ahora bien, la forma concreta que toma
vara mucho de uno a otro, especialmente si comparamos los lenguajes
La memoria dinmica se define como el espacio de almacenamiento
de datos que se adapta a las necesidades del programa.
Dimensionamiento
en tiempo de compilacin
El dimensionamiento en tiem-
po de compilacin es especial-
mente enojoso, porque nos
obliga a determinar una
dimensin a priori (que quiz
no se conoce con exactitud),
que adems se debe fijar para
siempre, a menos que se
recompile el programa.
El problema de la
dimensin del vector
De hecho, el tercer problema
realmente no se solucionar,
porque la memoria del ordena-
dor es finita y se puede agotar
sea cual sea el mtodo elegido
de almacenamiento de
elementos.
FUOC P01/75001/00075 60 Tipos abstractos de datos
imperativos y los orientados a objetos, que imposibilitan la adopcin de
un modelo universal:
En el caso de los lenguajes imperativos, la memoria dinmica se acostum-
bra a gestionar mediante datos declarados de un tipo nuevo (en realidad,
un constructor de tipo) y algunas operaciones ofertadas por este tipo.
En el caso de loslenguajes OO, la memoria dinmica es el mecanismo usa-
do por defecto para almacenar los objetos que forman parte del programa,
y su gestin forma parte de la semntica de las conocidas operaciones de
creacin y destruccin de objetos.
A continuacin, presentaremos dos implementaciones diferentes de este concepto,
suficientemente representativas del dominio de los lenguajes de programacin: la
implementacin en Pascal y en Java. En el resto de la asignatura tomaremos este l-
timo como el modelo de memoria dinmica en la notacin algortmica, dada su
simplicidad y el uso de Java como lenguaje de trabajo en la asignatura.
6.1. La memoria dinmica en Pascal
La piedra angular del mecanismo de memoria dinmica en Pascal es la exis-
tencia de un constructor de tipo llamado puntero (en ingls, pointer).
En trminos de implementacin, el espacio libre se gestiona por el sistema
operativo que responde a las demandas del programa, y un puntero no es ms
que una direccin de memoria que representa la posicin de inicio del objeto
de tipo T, con el aadido de un mecanismo de control de tipo para impedir el
uso indebido de los objetos.
Si se usan punteros, se puede obtener espacio para guardar objetos de un tipo
determinado. Este espacio se puede retornar cuando el programa no necesita
el objeto; estas operaciones se traducen en la existencia de dos acciones que
involucran un puntero p de tipo ^T:
Accin new(p): obtiene de la memoria dinmica el espacio necesario para
guardar un valor de tipo T, y guarda en p el puntero que acta como cami-
no de acceso a este objeto.
Accin dispose(p): destruye, es decir, retorna a la memoria dinmica el
objeto apuntado por p, de forma que se vuelve inaccesible desde el progra-
ma para siempre. La invocacin de esta accin es el nico mecanismo exis-
tente para destruir un objeto creado mediante new.
Adems, dos punteros se pueden comparar y asignar de la forma habitual en
Pascal usando los operadores relacionales y la asignacin, respectivamente.
Una variable de tipo puntero a T, denotado por ^T, donde T es un tipo
de datos cualquiera, representa un apuntador a un objeto de tipo T.
Otras estrategias
interesantes
Tambin habra sido interesan-
te estudiar la estrategia del
lenguaje C, similar a la de
Pascal, pero menos robusta,
y fuente inagotable de errores
de programacin. Sin embar-
go, en estos materiales
didcticos no tenemos espacio
suficiente.
Puntero y apuntador
No confundis la nocin de
puntero con la ms abstracta
deapuntador. Un apuntador es
un dato que apunta a algo,
que puede tomar la forma de
un entero o de un puntero.
Funcionalidades
adicionales
Varias implementaciones de
Pascal pueden ofrecer otras
funcionalidades adicionales,
pero las que aqu menciona-
mos son las estndar.
Destruccin de objetos
con dispose
Los valores creados con new no
se destruyen automticamente
cuando acaba la ejecucin del
procedimiento en el que se ha
creado (con la nica excepcin
del bloque correspondiente al
programa principal); sta es una
diferencia fundamental con los
objetos estticos habituales.
FUOC P01/75001/00075 61 Tipos abstractos de datos
Desde el momento en que se ha obtenido espacio para un objeto hasta que se
libera, el objeto se referencia mediante su puntero escribiendo el smbolo ^tras
el nombre del puntero. Cuando una variable de tipo puntero no apunta a nada
(antes de asociarle un objeto, despus de asociarle uno, o cuando lo forman ex-
plcitamente mediante una asignacin), tiene un valor especial que llamare-
mos puntero nulo, que en Pascal se escribe nil. Aplicar el operador ^o la accin
dispose sobre un puntero nulo provoca un error.
A continuacin se muestra la representacin del tipo y la codificacin de dos
operaciones en una implementacin para los sacos Pascal usando memoria di-
nmica. De acuerdo con el esquema dado, el tipo auxiliar de los elementos de
la cadena se define recursivamente. El invariante es similar en el caso de los
vectores, adaptando la notacin y sabiendo que el sitio libre no es referencia-
ble desde la representacin.
type
pnodo =^nodo;
nodo =record
v: Elem;
enc: pnodo
end;
Saco =record
tamao; integer;
prim, ult: pnodo
end;
(*invariante (s: Saco)
s.prim nil s.ult nil s.ult cadena(s.prim)
s. tamao =||cadena(s.prim)|| 1
cadena(nil) ={nil}
p nil cadena(p) cadena(p^.enc) {p}*)
procedure inserta (var s: Saco; v: Elem);
var temp: pnodo;
begin
new(temp); temp^.v :=v;
temp^.enc :=s.prim^.enc :=temp;
s.tamao :=s.tamao +1
end;
procedure borra (var s: Saco; v: Elem);
var ant, act: pnodo; encontrado: booleano;
begin
ant :=s. Prim; act :=s.prim^.enc; encontrado :=false;
while (act nil) and (not encontrado) do begin
if act^.v =v then encontrado :=true
else begin ant :=act; act :=act^.enc end
end;
Fijmonos en que
el cambio de vector por
punteros no afecta a los algo-
ritmos de las funciones, sino
slo a la notacin.
Tipo auxiliar
Es necesario declarar un tipo
auxiliar pnodo para evitar una
definicin de tipo recursivo, no
aceptada por los compiladores
de Pascal.
La memoria dinmica
De alguna manera, se puede
decir que la memoria dinmica
es un atributo implcito, accesi-
ble desde todas las implemen-
taciones existentes.
FUOC P01/75001/00075 62 Tipos abstractos de datos
Con vistas al clculo de la eficiencia espacial, consideramos que un apuntador
ocupa un espacio O(1); conviene tener siempre presente que si presenta un valor
nulo, habr un objeto apuntado que tendr su misma dimensin. En el caso de
calcular el espacio real de una estructura de datos, hay que conocer la dimensin
exacta de un apuntador. Por otro lado, la indireccin propia del operador tam-
bin se considera O(1) por lo que respecta a la eficiencia temporal.
6.2. La memoria dinmica en Java
La gestin de la memoria dinmica cambia radicalmente en Java. Se puede de-
cir que la gestin es mucho ms transparente por varios motivos:
1) No hay una diferencia entre datos estticos y datos dinmicos porque to-
dos son dinmicos. Los objetos se crean y se destruyen dinmicamente; slo
existen mientras tienen una vida til en el programa*.
2) Los datos (atributos, parmetros y variables) declarados de una clase determi-
nada nunca contienen los valores mismos, sino apuntadores a los valores. Por
este motivo, no hay ningn tipo especial equivalente a los punteros de Pascal.
3) La creacin del objeto est relacionada con la inicializacin de sus atributos
mediante los mtodos constructores. Este vnculo favorece que el objeto no se
cree hasta que se necesite (obviamente, una programacin deficiente puede
contradecir este principio general).
4) Por omisin, la destruccin de un objeto es automtica; deja de ser respon-
sabilidad del programador. Hay una herramienta llamada recolector de basuras
que detecta los objetos que ya no son tiles y retorna el espacio que ocupaban
en la memoria dinmica. Si bien el espacio se recupera automticamente, Java
no determina en qu momento se hace la recoleccin. Eso s, es posible invo-
car explcitamente al recolector y provocar la recuperacin inmediata.
Si cuando se intenta crear un objeto no hay suficiente memoria dinmica dispo-
nible (incluso despus de que el recolector sea implcitamente invocado cuando
se produce esta situacin), el new activa la excepcin OutOfMemoryException.
if encontrado then begin
ant^.enc :=act^.enc; dispose (act);
s.tamao :=s.tamao 1
end
end;
La memoria dinmica
se denomina heap en Java
y en otros lenguajes.
* Un objeto deja de ser til
cuando no hay ningn apuntador
que d acceso al mismo.
Destacamos la diferencia
con respecto a los datos de
tipo definido, que s contienen
los valores. Recordad la exis-
tencia de clases envoltura para
los tipos predefinidos, introdu-
cida en la asignatura Funda-
mentosde programacin II, que
permite usarlos como clases
cuando convenga.
Lectura recomendada
Para ms informacin sobre
el recolector de basuras en
Java, consultad la obra
siguiente:
K. Arnold; J. Gosling (1998).
The Java Programming
Language (2. ed., pg. 322).
Reading (Massachusetts):
Addison-Wesley.
FUOC P01/75001/00075 63 Tipos abstractos de datos
Una forma diferente y no tan elegante de adivinar si hay espacio para crear obje-
tos es usar el mtodo-funcin freeMemory, que retorna el nmero de bytes libres.
Por ltimo, se tiene que decir que el puntero nulo se denota con null.
Podis encontrar varias implementaciones con punteros de Java en la biblio-
teca Java de la asignatura.
6.3. La asignacin y la igualdad
Es necesario hacer una breve reflexin sobre el comportamiento de la asigna-
cin y la igualdad en presencia de punteros. El significado de estas dos cons-
trucciones algortmicas est claro:
x :=y significa asignar a x el valor que tiene y.
x =y significa comparar si x e y tienen el mismo valor.
Cuando x e y son punteros, el significado es exactamente el mismo: se asignan
o comparan los punteros, y no los datos apuntados. No hay ninguna diferen-
cia operativa, pero s una diferencia conceptual, porque la existencia de pun-
teros est relacionada con cuestiones de implementacin y tendra que ser
transparente a los usuarios.
Ejemplo de asignacin con punteros en Pascal
Veamos un ejemplo en Pascal que ilustra la operacin de asignacin con punteros. Si dis-
ponemos de tres conjuntos de variables, uno de tipo t definido como una tupla de dos
campos enteros x e y, el otro de tipo predefinido (entero) y un tercero de tipo entero pun-
tero a t, la secuencia de instrucciones siguientes tiene el significado que muestra el dibujo
de la derecha de la figura:
Las siguientes comparaciones dan los resultados que vemos a continuacin:
a = b cierto i = j cierto p= q falso
a = c cierto i = k cierto p= r cierto
Destacamos especialmente la comparacin que da falso. Pese a que los valores apuntados
por p y q son iguales, p y q son diferentes (apuntan a zonas diferentes de memoria). En
cambio, p y r s son iguales, dada la asignacin realizada.
Significado del puntero
A partir de ahora, usamos el
trmino puntero como referen-
cia a cualquier dato de memo-
ria dinmica, no tanto como el
constructor de tipos de Pascal
y otros lenguajes.
FUOC P01/75001/00075 64 Tipos abstractos de datos
En Java la situacin es similar, excepto el caso de las tuplas (inexistentes en este lenguaje):
implcitamente se accede a todos los objetos mediante su puntero.
Muchas veces realmente se quieren asignar y comparar los datos apuntados y
no los punteros mismos. En estos casos, no se pueden utilizar ni la asignacin
ni la igualdad del lenguaje, sino funciones o mtodos especiales. La aproxima-
cin es diferente en Pascal o Java:
1) En Java, la clase Object define un mtodo-funcin llamado Clone que dupli-
ca un objeto. El objeto creado es diferente, de forma que si hay cambios en uno
no afectan al otro.
Ejemplo de utilizacin del mtodo-funcin Cl one
En la siguiente figura se muestra un fragmento de cdigo Java que contiene el mtodo-
funcin Cloney su efecto mediante un grfico:
Toda clase que quiera ofrecer el mtodo Clone tiene que implementar adems
la interfaz Cloneable.
El comportamiento por omisin de Clone se limita a duplicar el estado del ob-
jeto duplicado. Sin embargo, fijmonos que los atributos duplicados sern
normalmente punteros a los objetos, de modo que los atributos del objeto
nuevo, en realidad, apuntan a los mismos objetos que los del viejo.
Ejemplo ilustrativo del comportamiento por omisin de Cl one
La siguiente figura ilustra la duplicacin de los estados del objeto duplicado:
Si este funcionamiento no se considera adecuado, entonces hay que definir el
mtodo Clone y clonar tambin los atributos componentes que no sean de tipo
predefinido.
Lo mismo sucede con la comparacin. Si se quieren comparar los objetos, hay
que utilizar el mtodo Equals de la clase Object. Por omisin, se comparan uno
a uno los valores de todos los atributos de la clase. Como antes, en el caso de
Observad la clase Object en el
subapartado 2.3.1. de este mdulo
didctico.
FUOC P01/75001/00075 65 Tipos abstractos de datos
los atributos punteros, se comparan los punteros y no los valores apuntados,
y si se quiere evitar este comportamiento, hay que redefinir el mtodo y com-
parar los atributos tambin con Equals.
2) La situacin es parecida con Pascal, si bien en este caso no hay mtodos pre-
definidos; conviene que los TAD implementen unas operaciones de asignacin
y comparacin similares a las de Java. Incluso hay que plantearse la existencia
de un mtodo de destruccin de la estructura, dado que no hay recolector de
basuras.
6.4. Riesgos del uso de la memoria dinmica
Al empezar el apartado se han comentado las ventajas del uso de memoria di-
nmica. Ahora conviene citar algunas desventajas, que se suman a las particu-
laridades mencionadas en el ltimo subapartado:
1) No es verdad que la memoria sea infinita: en cualquier momento durante
la ejecucin del programa se puede agotar el espacio, con el agravante de no
conocer a priori la capacidad mxima de la estructura. Nuestros programas ten-
dran que estar preparados para esta eventualidad.
sta es una diferencia fundamental con los vectores dimensionados en tiempo
de compilacin, como los de Pascal. Si usamos vectores, tenemos asegurado
que en la estructura cabrn tantos elementos como posiciones tiene el vector.
2) Los punteros son referencias directas a la memoria, por lo que es posible que
se modifiquen insospechadamente datos (incluso el cdigo, si el sistema opera-
tivo y/o el compilador no lo controlan) en otros puntos del programa a causa
de errores algortmicos. Como consecuencia, la depuracin del programa es ms
complicada, porque puede ser necesario estudiar la ocupacin de la memoria.
Tambin aqu, en una comparacin con los vectores, los punteros salen mal-
parados. La referencia A[k] nunca puede modificar ningn otro dato que no
seaA. En cambio, la referencia p, donde p es un puntero asociado a un tipo o
clase t, se puede referir a cualquier dato de tipo o clase t, segn la historia de
asignaciones del programa.
3) Varios puntos pueden designar un mismo objeto; en este caso, la modifi-
cacin del objeto usando un puntero determinado tiene como efecto lateral la
modificacin del objeto apuntado por el resto de los punteros.
Como conclusin, hay que evitar tanto como sea posible el uso de la
asignacin y la comparacin del lenguaje y usar mtodos y funciones
que hemos comentado. Es la nica forma de asegurar un comportamien-
to uniforme de las operaciones de los TAD.
Deteccin del agotamiento
de la memoria dinmica
Habitualmente, los lenguajes
de programacin ofrecen
algn mecanismo o convencin
para detectar el agotamiento
de la memoria dinmica.
FUOC P01/75001/00075 66 Tipos abstractos de datos
Ejemplo de varios punteros que designan un mismo objeto
Pensemos en el lenguaje Pascal. Consideremos el siguiente fragmento de cdigo:
Este cdigo presenta la caracterstica de que la misma referencia sobre q aplicada en dos
lugares diferentes da resultados diferentes, a pesar de que no haya cambios que involu-
cren a q entre estos dos sitios.
4) Una particularizacin del problema mencionado en el punto anterior son
las llamadas referencias colgadas. Una referencia resulta colgada cuando el efec-
to lateral consiste en liberar el valor apuntado. Esta situacin provoca errores
de ejecucin en un porcentaje muy elevado de casos.
Ejemplo de referencia colgada
Veamos el siguiente fragmento de cdigo:
Se dice que p queda colgando, en el sentido que su valor es diferente a nil, pero no apunta
a ningn dato vlido. Una referencia a p^tiene efectos impredecibles.
5) En los lenguajes sin recoleccin automtica de basuras aparece un proble-
ma simtrico al anterior: la creacin de basura, que consiste en la aparicin de
valores inaccesibles desde el programa.
Ejemplo de creacin de basura
Consideramos el siguiente fragmento de cdigo:
Este cdigo provoca que el dato inicialmente asociado a p resulte inaceptable despus de
la ltima asignacin, pese a que existe porque no se ha destruido explcitamente.
Eventualmente, la basura puede provocar errores de ejecucin porque se en-
gaa al sistema gestor de memoria dinmica.
6) Finalmente, recordemos que ya se ha hablado ampliamente del problema
de uso de asignaciones y comparaciones con punteros.
var p, q:^t; (*supongamos que t tiene un campo entero v*)

new(q); q^.v ;=2;


writeln(q^.v); (*se escribe el valor 2 *)
p :=q; p^.v :=3;
writeln(q^.v); (*se escribe el valor 3 *)
var p, q: ^t;

new(p); q :=p; dispose(q);


var p, q: ^t;
new(p); new(q); p :=q
FUOC P01/75001/00075 67 Tipos abstractos de datos
Resumen
El objetivo principal de este mdulo ha sido introducir detalladamente el con-
cepto de tipos abstractos de datos (TAD), su definicin mediante los mecanis-
mos de la programacin orientada a objetos y su implementacin mediante
varias estrategias:
1) Primero hemos hecho un repaso de las nociones de orientacin a objetos
que usaremos mucho a lo largo de la asignatura, especialmente en este mdu-
lo. Nos hemos centrado en todo aquello que tiene que ver con las clases y sus
componentes (atributos y mtodos), y las relaciones entre clases. Tambin he-
mos aadido alguna definicin nueva, de inters para nuestra asignatura.
2) En segundo lugar, hemos desarrollado una jerarqua de clases que integra
todos los TAD que veremos a lo largo de esta asignatura.
a) Hemos definido como raz de la jerarqua el concepto de contenedor de ele-
mentos, con las operaciones comunes a todos los TAD (que son muy pocas),
y poco a poco hemos ido creando las especializaciones necesarias.
b) Hemos definido cinco tipos principales de contenedores, dada la poltica de
insercin, supresin y consulta y, para cada uno, diferentes variantes que for-
man los TAD que finalmente se estudian en otros mdulos de esta asignatura.
c) Tambin hemos integrado en la jerarqua diferentes variantes de contene-
dores, de forma que cada uno tiene una jerarqua propia (si ms no, concep-
tualmente): contenedores acotados, contenedores recorribles y otros.
d) A continuacin, hemos definido una jerarqua aparte para integrar los pa-
rmetros de las clases (que son genricas).
e) Por ltimo, se ha dedicado un subapartado a estudiar la traduccin de esta
jerarqua a una jerarqua Java.
3) Por lo que se refiere a la implementacin, hemos distinguido tres partes:
representacin del tipo mediante una estructura de datos adecuada, estableci-
miento del invariante de la representacin y codificacin de las operaciones.
a) Larepresentacin del tipo se plasma con los constructores de tipos habitua-
les y mediante el uso de la memoria dinmica, que se introduce en el apartado 6.
b) El invariante, por su parte, toma la forma de un predicado booleano que es-
tablece los valores vlidos que pueden tomar los atributos de la representacin.
Observacin
El repaso hecho en el apartado 1
de este mdulo didctico no
pretende ser un sustitutivo del
material docente de Fundamen-
tosde programacin II, sino slo
un compendio de consulta
rpida. En el caso de dudas,
consultad el mencionado
material docente.
Consultad los mdulos Secuencias
y rboles, Funciones y conjuntos
y Relaciones de esta asignatura.
FUOC P01/75001/00075 68 Tipos abstractos de datos
c) La codificacin se hace mediante mtodos del lenguaje de programacin
elegido.
Se discute la forma que toman estas construcciones en Java.
4) El estudio del comportamiento de las implementaciones se hace desde
el punto de vista de su eficiencia temporal y espacial. Se utiliza la notacin
O-grande, que expresa la eficiencia como una funcin sobre el volumen de
los datos de entrada. El clculo de esta funcin se lleva a cabo a partir de
las construcciones de la notacin algortmica, tanto de las instrucciones
(para la eficiencia temporal) como de los constructores de tipos (para la efi-
ciencia espacial).
5) Finalmente, nos hemos dirigido al estudio de las estrategias de implemen-
tacin ms habituales que usaremos a lo largo de la asignatura, clasificadas en
dos grandes familias, y hemos aplicado los conceptos tericos sobre un caso
concreto, la implementacin del TAD de los sacos de elementos.
a) Lasestrategias secuenciales se caracterizan por el almacenamiento conse-
cutivo de los elementos en un vector, dividido en dos partes: la parte libre y la
parte ocupada. Hemos comentado los problemas de eficiencia de esta repre-
sentacin dados los movimientos de elementos exigidos para mantener el
agrupamiento. Hemos estudiado diferentes variantes de esta idea, como pue-
den ser el marcaje de posiciones liberadas en la parte ocupada y la ordenacin
de los elementos para favorecer las consultas.
b) La otra familia, las estrategias encadenadas, rompe la secuencialidad de
los elementos y as se evitan los movimientos. Primero hemos implementado
la estrategia usando vectores, lo que implica que el espacio libre tambin se
puede gestionar de forma encadenada; lo hemos llamado pila de sitios libres.
Hemos comprobado la mejora en general de la representacin, a cambio del
espacio adicional para romper la secuencialidad, los encadenamientos.
A continuacin hemos hablado de la memoria dinmica como forma alterna-
tiva de implementar estructuras encadenadas, con la caracterstica de que la
dimensin de la estructura se ajusta al nmero de elementos realmente guar-
dados. Hemos presentado el mecanismo en dos lenguajes concretos, Pascal y
Java, representativos del caso imperativo y orientado a objetos, si bien cada
lenguaje tiene sus particularidades. Finalmente, hemos visto peculiaridades e
inconvenientes en el uso de memoria dinmica, que hay que tener en cuenta
a la hora de elegir la estrategia final.
FUOC P01/75001/00075 69 Tipos abstractos de datos
Actividades
1. Hemos comentado que la jerarqua de TAD dada no se explica exhaustivamente por mo-
tivos de espacio. Os proponemos que la ampliis: pensad nuevas funcionalidades de los TAD
existentes, y pensad otros TAD que se podran integrar en la jerarqua.
2. Definid completamente algunas clases ms de la jerarqua, de forma similar a las que se
han definido en este mdulo.
3. Modificad la implementacin de los sacos propuesta en este mdulo aadiendo marcas.
Repetid el proceso ordenando el vector.
4. Si tenis a vuestro alcance algn libro de C o de C++, estudiad el mecanismo de memoria
dinmica del lenguaje. Comparadlo con los dos que se han visto aqu.
Ejercicios de autoevaluacin
1. Si reflexionsemos un poco, seguro que se nos ocurriran ms clases de contenedores, por
ejemplo, las matrices. Una matriz es un contenedor de elementos numricos (que, al menos,
se tienen que sumar y multiplicar) con operaciones de crear la matriz llena de ceros, definir
el valor de una coordenada, consultarlo, etc. Adems, existen ciertas clases de matrices, como
las matrices cuadradas, que permiten efectuar alguna operacin particular. Ampliad la jerar-
qua de contenedores aadiendo este nuevo tipo.
2. Calculad el coste del siguiente algoritmo de clculo del factorial:
3. Uno de los algoritmos de ordenacin de vectores ms conocidos es la ordenacin de la bur-
buja. Analizad su cdigo y determinad su eficiencia.
4. Codificad las operaciones de insercin y supresin de elementos en una representacin
doblemente encadenada implementada con vectores. En las dos operaciones, se pasara
como parmetro la posicin tras la cual se inserta, o bien la que se borra. Poned un elemento
fantasma en la estructura.
5. En una estructura lineal doblemente encadenada implementada sobre un vector, si la di-
mensin del vector es suficientemente pequea para codificar el valor de los dos encadena-
mientos con un nico nmero entero que caiga dentro del alcance de la mquina, puede ser
funcion factorial (n: entero) retorna entero
var i, fact: entero
(1) fact :=1; i :=2
(2) mientras i n hacer
(3) fact :=fact * i
(4) i :=i +1
(5) fmientras
(6) retorna fact
ffuncion
accion burbuja (ent sal v: vector [1n] de entero)
var i; j: entero
(1) i :=1
(2) mientras i <n hacer
(3) j :=n
(4) mientras j >i hacer
(5) si v[j 1] >v[j] entonces
(6) aux :=v[j]; v[j] :=v[j 1]; v[j 1] :=aux
(7) fsi
(8) j:=j 1
(9) fmientras
(10) i :=i +1
(11) fmientras
faccion
Leed la introduccin del apartado 2
de este mdulo didctico.
Podis ver la implementacin de los
sacos en el subapartado 5.1.2.
de este mdulo didctico.
FUOC P01/75001/00075 70 Tipos abstractos de datos
que slo haga falta un campo para representar los dos encadenamientos. Calculad la relacin
que tiene que haber entre la dimensin del vector N y el mayor valor entero de la mquina,
maxent, representable con k bits, y formulad unos mtodos-funciones de consulta y modifi-
cacin de los dos encadenamientos codificados en este nico campo (cons_suc, cons_pred,
mod_suc y mod_pred).
6. Implementad un TAD para los polinomios de una variable con coeficientes enteros y ex-
ponentes naturales con las siguientes operaciones:
cero(): crea el polinomio cero.
aade (k: entero, n: Nad): aade al polinomio el trmino k.x
n
.
res = eval (c: Entero): evala el polinomio en un punto.
k =coef(n: Entero): retorna el coeficiente del trmino de grado n.
sum(p: Poli): suma de polinomios.
Suponed que no habr ms de M trminos con coeficiente diferente de cero, si bien el mayor
exponente puede ser mayor que M. Usad las tcnicas: secuencial, secuencial ordenado (por
exponente), encadenamiento ordenado por vectores y encadenamiento ordenado con me-
moria dinmica. Incluid tambin la implementacin suponiendo que todos los exponentes
de trminos de coeficiente diferente de cero estn entre 1 y M. Comparad los resultados me-
diante una tabla comparativa.
Podis utilizar la tabla comparativa
del subapartado 5.3. de este
mdulo didctico.
FUOC P01/75001/00075 71 Tipos abstractos de datos
Solucionario
1. Una posible solucin a la propuesta del enunciado de aadir las matrices a la jerarqua es
la que explicamos a continuacin.
Consideramos que las matrices son contenedores acotados (normalmente, las matrices ma-
temticas se conciben con unas dimensiones fijas). crea? representa la matriz cero. La funcin
lleno? seguramente no tiene mucha utilidad, pero se deja aqu. No hay funcin borra; se con-
sidera que un elemento (una posicin) se borra cuando se aade un cero a la coordenada da-
da. Las diferentes funciones deberan tener preocondiciones que establecieran la correccin
de los parmetros.
A partir de este TAD, derivamos otro para las matrices cuadradas. Al menos, este tipo de ma-
trices tambin permite el clculo de determinantes.
2. El clculo del coste del algoritmo es el siguiente:
En la lnea (1) damos directamente el coste de las dos asignaciones; en la lnea (2), el de la
expresin; en las lneas (3) y (4), el de cada asignacin. En la lnea (5), multiplicamos el coste
O(1) del bucle por el nmero de vueltas n 1 y obtenemos O(n). En todas partes aplicamos
la propiedad d de la notacin O.
3. El algoritmo de ordenacin de la burbuja es la composicin secuencial de la asignacin de
la lnea (1), que tiene coste O(1), y el bucle de las lneas (2) (11), de forma que:
T(burbuja) = T((1)) + T((2) (11)) = O(1) + T((2) (11)) = T((2) (11)).
El bucle est compuesto de cuatro partes: la expresin de la lnea (2), las asignaciones de las lneas
(3) y (10) y el bucle de las lneas (4) (9). Puesto que los tres primeros factores son O(1), es evi-
dente que el coste del bucle interno determina el coste de cada paso del bucle externo.
funcion factorial (n: entero) retorna entero
var i, fact: entero
(1) fact := 1; i := 2 (1) + (1) = (1)
(2) mientras i n hacer (1) +
(3) fact := fact i (1) + +
(4) i := i + 1 (1) =
(5) fmientras O(1) (n 1) = O(n)
+
(6) retorna fact O(1)
O(n)
Consultad la eficiencia temporal en
el subapartado 4.1. de este mdulo
didctico.
FUOC P01/75001/00075 72 Tipos abstractos de datos
Ahora bien, el bucle interno tiene una particularidad: se ejecuta un nmero de veces cambia-
ble, que depende del valor de la variable i, que se va reduciendo. Este hecho desaconseja apli-
car la primera regla de clculo de la eficiencia del bucle, por lo que usamos la segunda (7b):
T((2) (11)) = k: 1 k n: c
k.
dondec
k
es el coste del bucle interno.
Dado que el coste de cada paso del bucle interno es constante secuencia de instrucciones
todas de coste O(1), su coste es igual al nmero de veces que se ejecuta. En la vuelta k-sima,
este nmero de veces es n-k. Como resultado tenemos:
T((2) (11)) = k: 1 k n: n k = (n 1) + (n 2) + ... + 0 = n (n 1)/2.
Este coste se incluye dentro de la categora representada por O(n
2
), y ste es, pues, el coste del
algoritmo.
4. Supongamos la siguiente como representacin del vector:
El algoritmo de insercin tiene como referencia un apuntador en el elemento anterior al lu-
gar donde se quiere insertar el elemento nuevo. El algoritmo de supresin tiene como refe-
rencia un apuntador al elemento que se borra.
5. Si pensamos en la representacin binaria del entero de la mquina tenemos los k bits que
menciona el enunciado como necesarios para representar los enteros:
Entonces podremos aprovechar la mitad de los bits para codificar la posicin del sucesor y la
otra mitad, para codificar la posicin del predecesor:
clase Nodo
atributos pblicos v: Elem; encIzq, encDer: Nat
fin clase
atributos
protegidos mximo, tamao: Nat
privados sl: Nat; A: vector [0mximo] de Nodo
mtodo inserta(p: Nat; v: Elem)
precondicin tamao < mximo, p cadena(0)
temp: Nat
temp := sl (* posicin que debe ocupar *)
sl := A[sl].encEsq (* usamos el encadenamiento de la izquierda
para formar pilas de sitios libres *)
A[temp].v := v
A[temp].encEsq := p; A[temp].encDr := A[p].encDr
A[A[p].encDr].encEsq := temp; A[p].encDr := temp
tamao := tamao + 1
mtodo borra(p: Nat)
precondicin tamao > 0
p cadena(0), p 0
A[A[p].encEsq].encDr := A[p].encDr
A[A[p].encDr].encEsq := A[p].encEsq
A[p].encEsq := sl; sl := p (* actualizamos la pila *)
tamao := tamao 1
Si k es impar
simplemente desapro-
vechamos el bit k-simo.
Ambas partes deben tener la
misma anchura.
FUOC P01/75001/00075 73 Tipos abstractos de datos
Por este motivo, la dimensin mxima del vector es N = 2
k/2
.
Las frmulas que nos permiten acceder a las dos mitades de la palabra p (expresadas ya en
notacin algortmica) son:
Los mtodos resultan de la siguiente manera:
DondepotDos es una constante definida como 2
(k div 2)
.
6. Slo damos las lneas generales de las diferentes implementaciones del TAD para los poli-
nomios de una variable con coeficientes enteros y exponentes naturales.
a) Secuencial: se divide el vector en parte ocupada y en parte libre. Cada insercin requiere
buscar si ya hay un trmino con el exponente dado (se evitan exponentes repetidos, porque la
cota de que se dispone es el nmero de trminos con coeficiente diferente de cero). La evalua-
cin requiere recorrer la parte ocupada. La bsqueda de coeficiente es una bsqueda lineal. Fi-
nalmente, la suma requiere ir con cuidado: si no se hace nada, sale cuadrtica sobre el nmero
de trminos, porque hay que buscar cada trmino de un polinomio linealmente en el otro. Es
mejor ordenar primero uno de los dos polinomios con un buen algoritmo de ordenacin, y en-
tonces las bsquedas se pueden hacer dicotmicas.
b) Secuencial ordenado: cada insercin requiere buscar y mover para mantener el orden. La
bsqueda de coeficiente es una bsqueda dicotmica. La suma es ahora un simple recorrido
de dos estructuras ordenadas, de coste lineal.
c) Encadenado ordenado por vector: las bsquedas vuelven a ser lineales. La suma se man-
tiene como en el caso anterior.
d) Encadenado ordenado con memoria dinmica: slo si hay cambios por lo que respecta
al espacio.
e) La ltima variante mencionada permite definir un vector de 1 a M e indexarlo directamente
con exponente. En general, la eficiencia es mejor en este caso. Esto sucede casi siempre, pero
que quede claro que slo se puede usar este esquema cuando el intervalo de valores utilizados
para indexar el vector se utilizar casi completamente. En cada posicin del vector tendremos
el coeficiente de aquel exponente, que valdr 0 si no se ha aadido nunca.
Al calcular los costes, supongamos que las asignaciones y comparaciones de naturales tienen
coste constante.
Sucesor: p div 2
(k div 2)
Predecesor: p mod 2
(k div 2)
mtodo consSuc(p: Entero): Entero
retorna p div potDos
mtodo consPred(p: Entero): Entero
retorna p mod potDos
mtodo modSuc(p: Entero, nuevoSuc: Enter): Entero
retorna (nuevoSuc potDos) +(p mod potDos)
mtodo modPrec (p: Entero, nuevoPred: Entero): Entero
retorna (p div potDos) puede Dos +nuevoPred
T(crea) T(aade) T(evala) T(coeficientes) T(suma) E
0
(Saco) Movimientos
a M M M M M log(M) 2k M + k No
b M M M log(M) M 2k M + k S
c M M M M M 3k (M + 1) + k No
d 1 M M M M (2k + p) (M + 1) + k No
e M 1 M 1 M k M No
k se define como E
0
(Nat), y p como el espacio de una referencia a un objeto en memoria dinmica.
FUOC P01/75001/00075 74 Tipos abstractos de datos
Glosario
apuntador
Valor que identifica un elemento dentro de una representacin de tipos.
apuntador de sitio libre
Valor que identifica la posicin que se ocupar en la prxima insercin, en una representa-
cin por vectores.
clase
Mecanismo de encapsulamiento de un tipo abstracto de datos en el contexto de nuestra
asignatura.
contenedor
Contenedor que tiene un capacidad mxima.
contenedor acotado
Contenedor que tiene una capacidad mxima.
contenedor recorrible
Contenedor que permite obtener sus elementos uno tras otro.
contenedor recorrible ordenado
Contenedor recorrible en el que los elementos se obtienen segn un orden determinado.
eficiencia
Aprovechamiento de los recursos del ordenador para una implementacin de TAD o, de for-
ma ms general, para un fragmento cualquiera de cdigo. Hablamos de eficiencia temporal y
eficiencia espacial, dependiendo del recurso medido.
encadenamiento
Campo asociado a los elementos del contenedor en las representaciones de tipos que permite
mantener el orden lgico de estos elementos en una representacin encadenada.
enlace
Sin.: encadenamiento
especificacin
Declaracin de sus operaciones de un tipo abstracto de datos y establecimiento de su com-
portamiento.
estructura de datos
Forma que toma la representacin del tipo mediante la combinacin de los constructores de
tipo y tipos predefinidos del lenguaje (algortmico o de programacin).
implementacin
Representacin de los valores del tipo, establecimiento del invariante de la representacin y co-
dificacin de las operaciones de un tipo abstracto de datos.
invariante de la representacin
Predicado booleano que determina los estados vlidos de una representacin de tipo.
invariante del bucle
Predicado booleano que determina las combinaciones vlidas de valores que pueden tomar
los objetos que intervienen en un bucle.
marca
Indicador lgico que seala a una posicin que est libre en una representacin de tipos por
vectores.
memoria dinmica
Espacio de almacenamiento de datos que se adapta a las necesidades del programa.
O
Abreviatura de O-grande.
O-grande
Notacin para la medida de la eficiencia, caracterizada para expresarla de acuerdo con la di-
mensin de los datos manipulados por las implementaciones o programas.
FUOC P01/75001/00075 75 Tipos abstractos de datos
pila de sitios libres
Conjunto de posiciones libres que estn encadenadas y gestionadas en forma de pila, en una
representacin encadenada por vectores.
puntero
Constructor de tipo para usar la memoria dinmica en algunos lenguajes de programacin, tpi-
camente en los imperativos. Tambin hablamos de datos punteros como valores de estos tipos.
recolector de basuras
Mecanismo que se encarga de descubrir y recuperar los pedazos de memoria dinmica que
los programas dejan de usar.
representacin del tipo
Parte de la implementacin de un tipo abstracto de datos que determina cmo se representan sus
valores mediante la eleccin de una estructura de datos adecuada.
representacin encadenada
Clase de representaciones de tipo caracterizada por el almacenamiento no consecutivo de los
elementos del contenedor.
representacin secuencial
Clase de representaciones de tipo caracterizadas por el almacenamiento consecutivo de los
elementos del contenedor.
TAD
Abreviatura de tipos abstractos de datos.
tipos abstractos de datos
Dominio de valores sobre los que se puede aplicar un conjunto de operaciones. Son los valores
y las operaciones los que determinan el tipo abstracto de datos.
Bibliografa
Arnold, K.; Gosling, J. (1998). The Java Programming Language(2. ed.). Reading (Massachu-
setts): Addison-Wesley
Franch, X. (1999). Estructuras de datos: especificacin, diseo e implementacin (3. edicin).
Barcelona: Edicions UPC (Politext nm. 30). Disponible en: http://www.edicionesupc.es
Weiss, M.A. (1995). Estructuras de datos y algoritmos. Washington Delaware: Addison-Wesley
Iberoamericana.
FUOC P01/75001/00075 76 Tipos abstractos de datos

You might also like