Professional Documents
Culture Documents
* listLibrary:
* EmptyListException.java
* Node.java
* List.java
* SinglyLinkedList.java
* TADs y algoritmos
* TAD: [Libro, p166]: "a systematic way of organizing and accessing data". Se tr
ata de un concepto anterior e independiente al concepto de objeto.
* Algoritmos: [Libro, p166]: "a step-by-step procedure for performing some task
in a finite amount of time". Se definen y usan en el diseo, la implementacin y el
uso de TADs (algoritmos que manipulan o se basan en TADs).
* Los TADs encajan con los principios de la Programacin Orientada a Objetos, cuyo
s lenguajes de programacin ofrecen mecanismos tiles (interfaces, clases, objetos,
herencia, genricos, etc) para realizarlos.
* Conceptos y terminologa
* Palabras clave a repasar y relacionar:
* Abstraccin.
* Encapsulacin.
* Ocultacin de informacin (relacionado con el mbito y la visibilidad).
* Independencia de la representacin.
* Modularidad, cohesin y acoplamiento.
* Organizacin jerrquica.
* Abstraccin:
* Acepcin del Diccionario de la Real Academia Espaola, 22 edicin:
"Separar por medio de una operacin intelectual las cualidades de un objeto para c
onsiderarlas aisladamente o para considerar el mismo objeto en su pura esencia o
nocin."
* Abstraccin funcional: atender a la funcin (funcionalidad, propsito, "el qu") ignor
ando la estructura interna ("el cmo").
* Propiedades y consecuencias de la abstraccin funcional:
* Encapsulacin (ocultacin de informacin): slo necesita conocerse la funcin, la estruc
tura queda oculta.
* Independencia de la estructura (o representacin): la misma funcin puede ser real
izada por diferentes estructuras (representaciones).
* Modularidad: resalta la cualidad de cpsula. Un mdulo (cpsula) debe tener alta coh
esin (ser autocontenido) y bajo acoplamiento (no depender de otras cpsulas).
* Relacin con parametrizacin y genericidad: una cpsula paramtrica instancia muchas cp
sulas concretas no paramtricas a travs de parmetros. La genericidad tiene que ver c
on el paso de parmetros ms sofisticados.
* Abstraccin en programacin
* Abstraccin funcional: la funcin se describe a travs de un interfaz y una especifi
cacin del comportamiento (la sintaxis y la semntica). La estructura interna se des
cribe mediante una implementacin que realiza la especificacin.
* Encapsulacin: se refiere a dos mecanismos interrelacionados: por un lado los qu
e permiten definir y crear cpsulas, y por otro los que permiten ocultar la inform
acin. Pueden estar combinados en un nico mecanismo. Ejemplo: clases de Java.
* Abstraccin de control: macros, subrutinas, programacin estructurada (condicional
es, bucles, etc), procedimientos y funciones, objetos y mtodos, mecanismos de sin
cronizacin y comunicacin en concurrencia, etc.
* Abstraccin de datos: lo ilustraremos en *Listas simplemente enlazadas.
* La definicin formal ms aceptada de TAD es la de "lgebras no libres": conjuntos de
valores manipulados en trminos de operaciones entre las cuales se cumplen leyes
que involucran a las operaciones de construccin. Ilustraremos esta idea en *Lista
s simplemente enlazadas.
* Listas simplemente enlazadas
* Motivacin de las listas simplemente enlazadas
* Una lista es una secuencia de elementos en la que se pueden encontrar, inserta
r y borrar elementos en cualquier posicin.
* Los elementos estn ordenados linealmente: primer elemento, segundo, etc.
* Asumimos que el tamao de la lista no est acotado y que sta puede crecer indefinid
*
while (p.element() != e2 && n <= list.size()) {
*
p = list.next(p);
*
n++;
*
}
*
// Aqu se cumple o bien 'p.element() == e2' (encontrado)
*
// o bien 'n > list.size()' (no encontrado).
*
if (p.element() == e2) list.addBefore(p,e1);
* }
* }
* EJERCICIO: Reescribir el cdigo del fichero 'ExampleUse.java' que vimos en *Repa
so de listas simplemente enlazadas pero usando nicamente listas con posiciones.
* Listas: comentarios y ejercicios
* Cul es el criterio para elegir entre los TADs lista? Respuesta: el uso de los mto
dos y la complejidad requerida de cada uno.
* Tradicionalmente los TADs (incluidos las listas) se usan para insertar, buscar
y borrar elementos directamente o a travs de ndices, no se usan abstracciones com
o 'Position<E>'. La JCF no lo usa, como veremos los temas *Interfaz java.util.Ar
rayList de la JCF y *6.3.4 List Iterators in Java. Sin embargo, 'Position<E>' es
un mecanismo til que permite obtener una buena complejidad.
* A la hora del diseo, pensad en las posibilidades para los mtodos de bsqueda, inse
rcin y borrado:
* put(e), remove(e) : 'e' elemento. < get(e)?
* put(i,e), remove(i) : 'i' ndice.
* put(p,e), remove(p) : 'p' posicin dada por una clase. < get(p)?
* EJERCICIO: Abstrae una posicin la nocin de ndice? Implementar 'IndexList<E>' usand
o 'NodePositionList<E>' como representacin.
* 6.4.2 Sequences
* Libro, Seccin 6.4.2, p264.
* Transparencias: iterators.pdf (de la 7 a la 11).
* Cdigo: Sequence.java (slo interfaz).
* El interfaz 'Sequence<E>' es la unin de los interfaces 'PositionList<E>', 'Inde
xList<E>' y 'Deque<E>'. Este ltimo no lo veremos en clase. Se describe en [Libro,
Seccin 5.3, 'Double-Ended Queues'].
ERRORES: En [Transparencia 7] slo se dice que las secuencias son la unin de "array
lists" y "node lists".
* Las secuencias disponen por tanto de mtodos que acceden mediante ndices y median
te posiciones. Se puede dar una implementacin razonable?
* Los mtodos 'atIndex' e 'indexOf' son el puente entre posiciones e ndices.
* Implementaciones posibles:
* Mediante cadenas enlazadas como *Repaso de listas simplemente enlazadas.
* Mediante vectores: un vector de posiciones (no de elementos como se ha visto e
n *6.1 Array Lists) donde las posiciones almacenan ndices [Transparencia 10]. Hay
que hacer desplazamientos (incrementar o decrementar el ndice almacenado en el n
odo) para los mtodos de insercin y borrado, incluidos las que manipulan nodos como
'addBefore', etc.
* EJERCICIO: Implementar una clase 'ArrayIndexSequence<E>' que implemente el int
erfaz 'Sequence<E>' mediante vectores de posiciones.
4 Conjuntos, iteradores, complejidad
* Conjuntos
* Material
* Cdigo: 'Conjuntos.zip' disponible en el Aula Virtual, contiene:
* ExampleUse.java
* setLibrary:
* Set.java
* BitVectSet.java
* La seccin 11.4 del libro trata de conjuntos ordenados con aplicaciones al probl
ema "union-find". No los estudiaremos aqu.
* Motivacin y definiciones de conjuntos
* Definicin y propiedades
* Al igual que las listas, los conjuntos son colecciones de elementos, con las s
iguiente diferencias:
1. No se almacenan elementos repetidos.
2. El orden de elementos es irrelevante.
3. La operacin observadora principal es el test de pertenencia de un elemento al
conjunto (por eso son irrelevantes el orden y la repeticin de elementos).
Consecuencias:
* La clase de los elementos debe proporcionar una operacin de igualdad (deben imp
lementar 'equals') o no se podr realizar el test de pertenencia. (Mencionamos aqu
los teoremas de decibilidad, etc).
* La operacin de bsqueda no tiene sentido.
* Operaciones modificadoras principales
* La insercin de un elemento en el conjunto si no est.
* El borrado de un elemento del conjunto si est.
* La unin, interseccin, y diferencia con otro conjunto. (S, las consideramos como o
peraciones modificadoras *Mutabilidad.)
* La operacin de complemento puede ofrecerse si el conjunto universal es represen
table.
* Mutabilidad
* Los conjuntos se estudian en matemticas informalmente ("naive set theory") y fo
rmalmente ("axiomatic set theory", Zermelo-Fraenkel, etc). Son una herramienta e
sencial en matemticas, meta-matemtica y fundamentos de la matemtica.
* En matemticas generalmente se tienen conjuntos inmutables. No hay operaciones d
e modificacin sino que se crean nuevos conjuntos. Por ejemplo, la operacin de inse
rcin es una funcin que devuelve otro conjunto, no se modifica el conjunto de parti
da.
* En algortmica lo ms usado son conjuntos mutables: conjuntos sobre los que invoca
mos mtodos modificadores de insercin, borrado, etc.
* Consideraremos los mtodos de unin, interseccin, etc, como modificadores. As la unin
de dos objetos conjunto 's' y 'r' ser realizada por 's.union(r)' o 'r.union(s)'.
En el primer caso 's' contiene la unin y en el segundo 'r' contiene la unin. Ambo
s conjuntos quedan modificados con el valor de la unin.
* Finitud y acotacin
* En matemticas un conjunto puede ser finito o infinito. La memoria de una comput
adora es finita. Distinguimos por tanto entre:
* Conjuntos con tamao acotado: tienen un tamao mximo fijo. Pueden representarse en
el lenguaje usando tipos de datos. Encarnan los conjuntos finitos matemticos. Una
vez alcanzado el tamao mximo no se pueden insertar ms elementos.
* Conjuntos con tamao no acotado: el tamao mximo es la memoria disponible. Aunque e
l tamao va cambiando (crece al insertar, decrece al borrar) el conjunto en todo m
omento es finito. Pueden representarse en el lenguaje mediante tipos de datos.
* Conjuntos infinitos: en el sentido matemtico. Se representan finitamente en el
lenguaje mediante el programa que genera los elementos. Por ejemplo, el conjunto
de los naturales (no un subconjunto finito sino todo el conjunto) estara represe
ntado por el programa que genera todos los naturales. Estos conjuntos son inmuta
bles. En Java no es inmediato cmo programar estos conjuntos, en otros lenguajes e
s ms fcil.
* Implementaciones y complejidad
* Conjuntos mediante listas
* Podemos utilizar los TADs de listas indexadas y de posiciones que hemos visto
o utilizar directamente cadenas enlazadas, etc, en la implementacin de conjuntos
mutables y no acotados.
* Control de duplicados:
0. Insertar comprobando duplicados:
* Insercin ms costosa: hay que recorrer la lista entera para detectar ocurrencias:
insertar = comprobar pertenencia + (opcional) aadir. Complejidad lineal O(n) en
el tamao 'n' de la lista.
* Ahorro de memoria: no hay duplicados.
* Cdigo del borrado ms sencillo: se borra la primera ocurrencia.
* El test de pertenencia recorre la lista entera en el caso peor.
* La unin 's.union(r)' *Mutabilidad recorre la lista 'r' insertando cada elemento
de dicha lista en la lista de 's'. Sea 'm' el tamao de la lista de 's' y sea 'n'
el tamao de la lista de 'r'. Cada elemento de la lista de 'r' se inserta en la l
ista de 's' invocando el mtodo de insercin sobre 's', que en el caso peor recorre
toda la lista de 's' para comprobar duplicados y por tanto tiene complejidad lin
eal O(m). Dicha insercin se realiza por cada elemento de la lista de 'r', con lo
que la complejidad de la unin es O(m*n). Para simplificar, la complejidad de la u
nin es por tanto cuadrtica O(n2) donde ahora 'n' se entiende como el tamao de la li
sta ms grande. (La justificacin formal de este razonamiento la explicaremos ms adel
ante en el tema *4.2 Analysis of Algorithms.)
1. Insertar sin comprobar duplicados:
O(n2)
union
member
remove
O(n)
add
Complejidad
Mtodo
* Insercin menos costosa: se inserta en la posicin ms ventajosa, p.ej., al final en
una lista indexada, al principio en una lista de nodos, etc, de forma que se te
nga complejidad constante O(1).
* Gasto de memoria: hay duplicados.
* Cdigo del borrado menos sencillo: se borran todas las ocurrencias.
* El test de pertenencia recorre la lista entera en el caso peor.
* La unin es ms eficiente pues la insercin no comprueba duplicados: cada elemento d
e la lista de 'r' hay que insertarlo en 's' sin controlar duplicados. La complej
idad de la unin es por tanto O(n*1) = O(n), lineal en el tamao 'n' de la lista de
'r'.
* En ambos casos el borrado es O(n), lo que cambia es la complicacin del cdigo.
union
member
O(n)
remove
O(1)
add
Complejidad
Mtodo
* La eleccin de control de duplicados depende de si se desea velocidad en ciertas
operaciones o ahorrar memoria. La clsica dicotoma en algortmica entre ahorro en ti
empo y ahorro en espacio que veremos durante todo el curso.
* EJERCICIO: Cmo se implementara la interseccin y la diferencia en cada caso y cul se
ran las respectivas complejidades?
* Conjuntos mediante vectores de bits
* Podemos usar un vector de booleanos, llamado tambin vector de bits, para implem
entar conjuntos mutables y acotados. A cada elemento del conjunto le corresponde
nicamente una posicin del vector. El booleano indica si el elemento est o no en el
conjunto.
* Conjunto universal: {A,B,C,D}
*
* Posiciones: A -> 0, B -> 1, C -> 2, D -> 3
*
* Conjunto {A,D} como vector de bits:
*
*
0
1
2
3
* |------+-------+-------+------|
* | true | false | false | true |
* |------+-------+-------+------|
* En Java, los ndices de los vectores slo pueden ser enteros 'int'.
* Para poder utilizar elementos como ndices su tipo debe ser finito numerable, en
correspondencia con un subconjunto finito de los enteros. En Java: tipos enumer
ados.
* En Java, todo tipo enumerado hereda de la clase 'Enum'. Ejemplo:
* public enum Dias { Lun, Mar, Mie, Jue, Vie, Sab, Dom; }
El enumerado 'Dias' es una clase que hereda de 'Enum<Dias>'. Las constantes enum
eradas (p.ej., 'Dias.Lun') son objetos de la clase. El compilador genera automtic
amente el cdigo para los mtodos heredados de la clase 'Enum', entre los que destac
amos:
* Mtodo 'ordinal' que devuelve el ndice de la constante enum dentro de la enumerac
in. Ejemplo: 'Dias.Lun.ordinal()' devuelve 0 y 'Dias.Dom.ordinal()' devuelve 6.
* Mtodo 'equals'.
* Mtodo 'toString'. Ejemplo: 'Dias.Lun.toString()' devuelve la cadena de caracter
es "Lun".
* Mtodo 'getDeclaringClass' que devuelve el objeto clase (API de reflexin) al que
pertenece la constante enum. Ejemplo: 'Dias.Lun.getDeclaringClass()' devuelve un
objeto de clase 'Class<Dias>'.
* Problema con la clase 'Enum': no ofrece un mtodo que devuelva cuntas constantes
tiene el enumerado (el "tamao" del enumerado). Se puede obtener ese valor usando
la API de reflexin.
* Estudiaremos en detalle esta implementacin en *Una librera de conjuntos.
* La JCF ofrece una implementacin: 'EnumSet'.
* Complejidad (lo veremos en *Una librera de conjuntos):
<-Conjuntos
O(n)
union
member
remove
O(1)
add
Complejidad
*Mtodo
hay que recorrer
medianteeltablas
vectordedel
dispersin
otro conjunto.
* Para conjuntos mutables acotados y no acotados.
* Las estudiaremos en *Funciones finitas, tablas de dispersin y diccionarios
* La JCF ofrece una implementacin: 'HashSet'.
* Conjuntos ordenados
* Cuando hay una relacin de orden total sobre los elementos. Aqu puede ser til la bs
queda. Hay representaciones eficientes y usos importantes:
* *Funciones finitas con dominio ordenado y rboles binarios de bsqueda.
* [Libro, Seccin 11.4 'Sets and Union/Find Structures']
* Una librera de conjuntos
* Diagrama de clases de setLibrary
*
Interfaz Set<E>
*
^
*
|
*
I |
*
|
* Clase BitVectSet<E extends Enum<E>>
*
* I: Implementa.
* El *Interfaz Set<E> es un interfaz de conjuntos no acotados. La clase de eleme
ntos 'E' puede ser cualquier tipo vlido de Java que implemente 'equals'.
* La *Clase BitVectSet<E extends Enum<E>> implementa conjuntos acotados. El tipo
'E' de los elementos slo puede ser un enumerado (un tipo que extiende la clase '
Enum<E>').
* Interfaz Set<E>
* Cdigo setLibrary/Set.java.
* Un interfaz de conjuntos mutables de tamao no acotado.
* Describimos los mtodos en clase.
* EJERCICIO: Implementar el interfaz 'Set<E>' mediante listas indexadas y median
te listas de nodos. Concretamente, implementar dos clases, 'IndexListSet<E>' y '
PositionListSet<E>'. La primera debe utilizar un atributo de clase 'ArrayIndexLi
st<E>' y la segunda un atributo de clase 'NodePositionList<E>' para almacenar lo
s elementos del conjunto. Implementar dos versiones para cada clase, una con con
trol de duplicados y otra sin control de duplicados. Comparar el cdigo de la inse
rcin, el borrado, y el test de pertenencia de las dos versiones. Concordar con lo
visto en *Conjuntos mediante listas.
* Clase BitVectSet<E extends Enum<E>>
* Cdigo setLibrary/BitVectSet.java
* Implementacin de conjuntos mutables acotados, elementos de tipo enumerado.
* Atributos:
cardinalidad
'size'
"bit-vector"
'bv'
Descripcin
*Variable
Hay que almacenar
o tamaoeldel
tamao
conjunto
por separado, una cosa es el nmero de elementos que p
odemos llegar a almacenar (tamao del vector) y otra el nmero de elementos que hay
almacenados (tamao del conjunto o cardinalidad).
* El constructor devuelve un conjunto vaco. No crea ni inicializa el vector. Se c
rear el vector en la primera insercin. Los dems mtodos de la clase debern considerar
si 'bv' es null o no.
* El conjunto est vaci cuando no tiene elementos. En trminos del interfaz, esto lo
determina el valor del mtodo 'isEmpty'. En la implementacin, el conjunto vaco tiene
dos representaciones: cuando 'bv' es null o cuando 'bv' es un vector con todas
sus posiciones a 'false'. La primera deja de tener efecto en cuanto se invoca 'a
dd'.
* Se crea el vector en la insercin debido al Problema con la clase 'Enum', como v
eremos abajo en la explicacin del mtodo 'add'.
* El mtodo 'reset' pone el tamao a cero y todo el vector a falso si ste est creado.
No ponemos 'bv' a null, aprovechamos el objeto vector ya creado para futuras ins
erciones.
* El mtodo 'member' devuelve falso si el vector es vaco (nada pertenece al conjunt
o vaco). Si no es vaco entonces devuelve el valor de verdad asociado a la posicin e
n el vector de la constante enum, la cual indica si el elemento est en el vector.
* El mtodo 'add' crea el vector en la primera insercin sobre un conjunto vaco.
El tamao del vector lo determina el nmero de constantes enum. Como vimos en Proble
ma con la clase 'Enum', dicha clase no ofrece un mtodo que proporcione el nmero de
constantes. Sin embargo, la clase 'Class<T>' de objetos clase (API de reflexin)
ofrece el mtodo 'getEnumConstants' para obtener un vector con las constantes de u
n enumerado 'T'. El cdigo de 'add' usa el mtodo 'getDeclaringClass' de 'Enum' para
obtener el objeto 'Class<T>' del enumerado y sobre ste se invoca el 'getEnumCons
tants' para obtener el nmero de constantes del enumerado.
Despus de crear el vector se inicializan todas las posiciones a falso (conjunto v
aco).
Finalmente, si el elemento no est en el conjunto se modifica su "bit" de verdad y
se incrementa el tamao.
* El mtodo 'remove' modifica el "bit" del elemento en el vector si el vector de b
its no es null (o sera un conjunto vaco que no contiene el elemento) y si el eleme
nto est en el conjunto.
* El mtodo 'union' debe acceder al vector de bits del conjunto argumento 's' para
poder realizar la operacin.
* Se comprueba que 's' referencia un objeto de clase 'BitVectSet'. De no ser as l
a unin no tiene efecto.
* Se realiza un "downcasting" para poder acceder al atributo 'bv' del conjunto '
s'. La variable 'bvs' ("bit-vector de s") referencia el vector de bits del conju
nto 's' que en este punto sabemos que es un objeto de clase 'BitVectSet'.
* Si 'bvs' es null la unin no tiene efecto. Si no es null se incorporan los eleme
ntos (bits a 'true') del vector 'bvs' al vector 'bv' slo cuando los elementos no
estn en 'bv' (cuando el bit en 'bv' est a falso).
* Si 'bv' es null entonces se copia ('clone') el vector de bits y el tamao del ot
ro conjunto.
* EJERCICIO: Realizar los ejercicios indicados en el cdigo.
* EJERCICIO: Comprobar que los mtodos cumplen con las complejidades estipuladas e
n *Conjuntos mediante vectores de bits (considerando el coste amortizado para la
insercin) e indicar la complejidad para el resto de mtodos que no aparecen en la
tabla.
* EJERCICIO: Aadir a la clase e implementar el mtodo 'void complement()' que reali
za la operacin de complemento sobre el conjunto.
* Ejemplo de uso
* Cdigo: ExampleUse.java.
* Ejemplo de uso de conjunto mutable acotado. Lo estudiamos y ejecutamos en clas
e.
* 6.3 Iterators
* Material
* Libro: Seccin 6.3.
* Transparencias: iterators.pdf (indicamos en este guin cules utilizamos, de la 7
a la 11 son las transparencias del tema *6.4.2 Sequences).
* Cdigo:
* IterableIndexList.zip (disponible en el Aula Virtual).
* Los siguientes ficheros de la librera net.datastructures del libro: PositionLis
t.java, ElementIterator.java y NodePositionList.java.
* Motivacin de los iteradores
* Muchos programas tienen que recorrer un TAD y hacer algo con los elementos. La
implementacin del recorrido puede hacerse "desde fuera" del TAD mediante bucles,
invocando los mtodos observadores del interfaz para ir accediendo a los elemento
s. Por supuesto, esto slo es posible si hay suficientes mtodos observadores que pe
rmitan realizar el recorrido.
* Ejemplo 1: Mostrar por pantalla los elementos almacenados en un objeto 'list'
que implementa el *Interfaz IndexList<E>:
0. Interfaces de TADs. En este caso los iteradores se implementan usando los mtod
os del interfaz y pueden usarse para iterar sobre objetos de cualquier clase que
implemente en interfaz.
1. Clases concretas que implementan interfaces de TADs. En este caso los iterado
res pueden implementarse usando mtodos del interfaz del que heredan las clases, o
los atributos internos de las clases, o ambos. Estos iteradores nicamente pueden
usarse para iterar sobre objetos de las clases concretas. Por ejemplo, dada la
clase 'C' que implementa el interfaz 'I', el iterador definido para objetos de '
C' slo puede usarse sobre objetos de dicha clase.
En la seccin *Cmo iterar sobre TADs detallaremos las dos alternativas.
La primera alternativa es ms deseable desde el punto de vista de abstraccin y reus
abilidad. En ese caso el cursor s ser un atributo del iterador. Pero puede no ser
posible realizarla porque no hay suficientes mtodos observadores (como en el Ejem
plo 3 que hemos visto en la seccin *Motivacin de los iteradores) o porque la itera
cin usando mtodos del interfaz es ineficiente.
* [Transparencia 2]: "Extends the concept of position". [Libro, p254]: "Thus, an
iterator extends the concept of the position ADT we introduced in Section 6.2.
In fact, a position can be thought of as an iterator that doesn't go anywhere". T
iene realmente sentido entender 'Position<E>' como un iterador sobre una coleccin
que contiene un nico elemento?
* Interfaces Iterator<T> e Iterable<T>
* Declaraciones
* El interfaz 'Iterator<E>' declara los mtodos que debe implementar todo objeto i
terador. El interfaz est en 'java.util.Iterator'.
* public interface Iterator<E> {
* public E next() ;
/* obligatorio implementarlo */
* public boolean hasNext() ; /* obligatorio implementarlo */
* public void remove() ;
/* no obligatorio, problemtico! */
* }
* El interfaz 'Iterable<E>' declara un mtodo 'iterator' que devolver un objeto ite
rador. Este interfaz es la pieza que nos permitir asociar iteradores a un TAD. El
interfaz est en 'java.lang.Iterable'.
* public interface Iterable<E> {
* public Iterator<E> iterator() ;
* }
* Significado de los mtodos de Iterator<E>
* Los nombres de los mtodos de 'Iterator<E>' no parecen intuitivos a primera vist
a. Detallamos su significado:
* 'hasNext' indica si el cursor del iterador referencia un elemento ("tienes un e
lemento?").
* 'next' devuelve el elemento al que referencia el cursor y avanza el cursor ("dm
elo y pasa al siguiente").
* Los mtodos se usan en bucles, donde 'hasNext' es la condicin que se comprueba an
tes de invocar 'next'. Retomando el ejemplo de mostrar elementos de un TAD por p
antalla *Motivacin de los iteradores. En pseudocdigo:
* while ("tienes algo?") {
* elem = "dmelo y pasa al siguiente";
* System.out.print(elem + " ");
* }
Veamos el Ejemplo 1 y 2 de *Motivacin de los iteradores con iteradores. El mismo
cdigo de bucle vale para cualquier TAD iterable, la nica diferencia est en qu objeto
iterador se usa:
Iterator<E> it = new ...; /* invocar constructor de iterador concreto */
E e = it.next();
while (it.hasNext()) {
System.out.print(e + " ");
}
en este ejemplo la variable 'e' es redundante y puede omitirse:
Iterator<E> it = new ...;
while (it.hasNext())
45. U: Usa.
Todas las implementaciones de 'TAD<E>' pueden usar 'TADIterator<E>' siempre que
implementen el mtodo 'iterator' como se ha indicado en el punto 3.
46. EJEMPLO: IterableIndexList.zip (disponible en el Aula Virtual). En este cdigo
redefinimos el *Interfaz IndexList<E> para poder iterar sobre listas indexadas.
Se implementa el iterador 'ElementIterator<E>'.
47. EJEMPLO: en los ficheros de la librera net.datastructures del libro PositionL
ist.java, ElementIterator.java y NodePositionList.java.
* 'ElementIterator<E>' implementa 'Iterator<E>' para 'PositionList<E>'. (Comprese
el cdigo con el 'ElementIterator<E>' de IterableIndexList.zip.
Curiosamente el cursor no referencia un elemento de tipo 'E' sino una posicin 'Po
sition<E>', lo cual no concuerda exactamente con el patrn que hemos descrito. Sin
embargo, el cursor podra referenciar el elemento llevndose cuenta en un atributo
nuevo la posicin de ste. Comparar con IterableIndexList.zip donde el cursor refere
ncia un elemento de tipo 'E' y otro atributo lleva cuenta del ndice que ocupa el
elemento en el vector.
* 'PositionList<E>' extiende 'Iterable<E>'. (El mtodo 'positions' es lo que hemos
llamado 'elements' en *Declaraciones y clases.)
* 'NodePositionList<E>' implementa el mtodo 'iterator' [Cdigo, lnea 160] y usa el i
terador en los mtodos 'toString' [Cdigo, lnea 216] y 'forEachToString' [Cdigo, lnea 2
02]. *Ejemplos de iteradores
* Iteracin con bucles 'while' y 'for'
* Bucles WHILE:
* TAD<E> tad = new ... ;
* E e;
* Iterator<E> it = tad.iterator();
* while(it.hasNext()) {
*
e = it.next();
*
/* se hace algo con 'e' */
* }
* Bucles FOR:
* TAD<E> tad = new ... ;
* E e;
* for (Iterator<E> it = tad.iterator(); it.hasNext(); ) {
* e = it.next();
* /* se hace algo con 'e' */
* }
* Se pueden declarar varios iteradores simultneamente sobre un mismo TAD:
* TAD<E> tad = new ... ;
* E e;
* for (Iterator<E> it1 = tad.iterator(); it1.hasNext(); ) {
* e = it1.next();
* for (Iterator<E> it2 = tad.iterator(); it2.hasNext(); it2.next())
*
System.out.print(e);
* }
* EJERCICIO: Cul sera la salida del cdigo anterior?
* Iteracin con bucle 'for-each' de Java
* [Libro, p256], [JP'05, p50]
* http://java.sun.com/docs/books/jls/third_edition/html/statements.html#24588
* Patrn de sintaxis:
* for (type elem : expr) { stmts }
Donde:
* La variable 'elem' tiene tipo 'type' y no ocurre en 'expr'.
* La expresin 'expr' tiene tipo 'Iterable<T>' o tipo array de T, con T un subtipo
o un "boxing" de 'type'.
* Semntica informal:
1. Cuando 'expr' es de tipo Iterable<T> el bucle se lee como "ejecuta 'stmt' par
a todo elemento 'elem' del iterable 'expr'". Se trata de una abreviatura de:
2. for (Iterator<type> it = expr.iterator(); it.hasNext(); ) {
3. type elem = it.next();
4. stmts
5. }
donde 'it' es una nueva variable que no ocurre en 'stmts'. (Ntese que 'elem' se d
eclara despus de usarse 'expr' y por eso 'elem' no puede ocurrir en 'expr'.)
Si no hay elementos para iterar ('hasNext' devuelve falso) no se ejecuta el cdigo
del for-each.
La variable 'elem' puede declararse localmente dentro del bloque del bucle 'for'
: "A local variable declaration can also appear in the header of a for statement
(14.14). In this case it is executed in the same manner as if it were part of a
local variable declaration statement" http://java.sun.com/docs/books/jls/third_e
dition/html/statements.html#14.4
Dada la equivalencia entre 'for' y 'while:
{
Iterator<type> it = expr.iterator();
type elem;
while(it.hasNext()) {
elem = it.next();
stmts
}
}
6. Cuando 'expr' es de tipo array de T se trata de una abreviatura de:
7. for (int j = 0; j < expr.length; j++) {
8. type elem = v[j];
9. stmts
10. }
Donde 'j' es una nueva variable que no ocurre en 'stmts'.
Ejemplo de uso de for-each:
public int sumaArray(int [] v) {
int suma = 0;
for (int i : v)
suma += i;
return suma;
}
* Dentro de 'stmt' no se tiene acceso al iterador (a una variable que referencie
el objeto iterador), slo al elemento 'elem'. No se pueden invocar 'next', 'hasNe
xt', ni 'remove'.
Esto significa que en principio 'for-each' debe usarse para iterar sobre todos l
os elementos (de ah su nombre "para-cada"). Para iterar slo sobre algunos elemento
s (por ejemplo, aquellos que cumplan una condicin) debe usarse el iterador direct
amente *Ejemplos de iteradores.
* Otras alternativas
* Otra forma de poder iterar sobre un TAD (utilizada tambin alguna vez en el cdigo
del libro) consiste en declarar el mtodo 'iterator' como mtodo propio de 'TAD<E>'
sin extender de 'Iterable<E>':
* import java.util.Iterator;
* public interface TAD<E> {
* ...
* public Iterator<E> iterator();
* }
Problema: 'TAD<E>' no es 'Iterable<E>'. No podemos usar el iterador en contextos
donde se espera un objeto iterable, por ejemplo, no podemos hacer *Iteracin con
bucle 'for-each' de Java.
* Tambin se puede asociar el iterador a una implementacin (clase) y no al interfaz
:
* Cdigo del interfaz 'TAD<E>':
* public interface TAD<E> /* no extiende Iterable<E> */ { ... }
* Cdigo de una implementacin:
* public class TADImpl1<E> implements TAD<E> {
* ...
* public Iterator<E> iterator() { return new TADImpl1Iterator<E>(this); }
* }
* Cdigo del iterador asociado a la implementacin 'TADImpl1<E>':
* public class TADImpl1Iterator<E> implements Iterator<E> {
* TADImpl1<E> tadImpl1;
* E cursor;
* public TADImpl1Iterator(TADImpl1<E> t) {
*
tadImpl1 = t;
*
... /* cdigo aqu que inicializa el valor del cursor */
* }
* public boolean hasNext()
{ /* cdigo aqu */ }
* public E next()
{ /* cdigo aqu */ }
* public void remove()
{ /* cdigo aqu */ }
Puede no ser necesario definir el cursor explcitamente como un atributo del itera
dor.
El constructor toma como parmetro un objeto de la clase 'TADImpl1<E>', no un obje
to de tipo 'TAD<E>'. Los mtodos 'hasNext' y 'next' pueden implementarse o bien us
ando los mtodos del interfaz 'TAD<E>' (porque 'TADImpl1<E>' implementa los mtodos
de 'TAD<E>') o bien accediendo directamente a los atributos de 'TADImpl1<E>' si
son pblicos.
Alternativamente, podra definirse 'TADImpl1Iterator<E>' como una clase anidada no
esttica ('non-static') dentro de 'TADImpl1<E>', pudiendo la primera acceder a lo
s atributos privados de la segunda. (Consultar en la [JLS'3E] los conceptos de c
lases 'nested', 'inner', 'local', y 'anonymous', as como la siguiente URL:
http://download.oracle.com/javase/tutorial/java/javaOO/nested.html
* El iterador 'TADImpl1Iterator<E>' slo puede usarse con objetos de clase 'TADImp
l1<E>'. No puede usarse con objetos de otras clases que implementen 'TAD<E>'. Es
as clases deben tener su propio iterador.
*
TAD<E>
Iterator<E>
*
^ ^
^
* I | | I
| I
*
| \
|
*
|
TADImpl1<E> ------------- U ---------------> TADImpl1Iterator<E>
* TADImpl2<E>
*
* E: Extiende.
* U: Usa.
* I: Implementa.
* Un comentario sobre la adecuacin de implementar iteradores en las clases.
Tomemos el ejemplo de los conjuntos como ilustracin *Iterfaz Set<E>. En un conjun
to no importa el orden de elementos. La iteracin sobre un conjunto a travs del int
erfaz no es posible, como hemos visto en el Ejemplo 3 de *Motivacin de los iterad
ores. Podramos haber definido un mtodo 'iterator' directamente en el interfaz, per
o al no haber ningn tipo de orden la iteracin de conjuntos no puede ser determinis
ta: dos conjuntos iguales pueden tener iteraciones distintas. Por ejemplo, sean
's' y 'r' variables de tipo *Interfaz Set<E> donde 's' almacena el conjunto resu
ltado de insertar 3 en el conjunto con slo el elemento 4, mientras que 'r' es el
resultado de insertar 4 en el conjunto con slo el elemento 3. Se tiene que 's.equ
als(r)' y 'r.equals(s)' son ciertos (pues 'equals' implementa la igualdad de con
juntos). Supongamos que tanto 's' como 'r' estn implementados mediante listas de
posiciones *Conjuntos mediante listas, concretamente como objetos de una clase '
ListSet<E>' que almacena los elementos del conjunto en un atributo de clase 'Nod
ePositionList<E>'. Supongamos adems que el mtodo 'add' de los conjuntos se impleme
nta insertando el elemento al principio (mtodo 'addFirst') de dicha la lista de p
osiciones. Las listas de 's' y de 'r' son diferentes e iterar sobre ellas produc
e distintos recorridos: 3,4 para 's' y 4,3 para 'r'.
En general, se puede definir un iterador para casi cualquier TAD de elementos es
tipulando que el iterador puede ser no-determinista (recorre los elementos de fo
rma arbitraria segn cmo estn disponibles en la implementacin del TAD). Pero entonces
la computacin que se realice con los elementos iterados debe dar el mismo result
ado para cualquier posible permutacin de todos los elementos. Por ejemplo, la sum
a de elementos dara el mismo resultado para cualquier recorrido. Sin embargo most
rar elementos por pantalla dara resultados diferentes.
En el caso de conjuntos finitos de enumerados 'BitVectSet<E>' el dominio de elem
entos 'E' est ordenado por el orden en el que aparecen las constantes enumeradas,
con lo que la iteracin sobre dos conjuntos 'BitVectSet<E>' iguales siempre recor
rer los mismos elementos en el mismo orden (como muestra el ltimo fragmento de cdig
o del Ejemplo 3 de la seccin *Motivacin de los iteradores).
Por tanto, las implementaciones pueden aadir ms condiciones sobre los elementos qu
e pueden hacer factible la iteracin determinista en su caso. Veremos ms ejemplos c
uando veamos TADs con orden.
* Ejemplos de iteradores
* Mostrar los 'n' primeros elementos de un array de caracteres 'v':
* Usando for-each:
* for (char c : v)
* if (n>0) {
*
System.out.print(c + " ");
*
n--;
* }
Se recorre todo el array. Se podra usar 'break', pero es un error de estilo:
for (char c : v)
if (n == 0) break;
if (n>0) {
System.out.print(c + " ");
n--;
}
Un principio de programacin estructurada [Bruce J. MacLennan, "Principles of Prog
ramming Languages: Design, Evaluation and Implementation"]:
"Structure: The static structure of the program should correspond in a simple wa
y to the dynamic structure of the corresponding computations."
Corolario para bucles: Debe salirse fuera de un bucle nicamente cuando la condicin
sea falsa, tenindose as un nico punto de salida a tener en cuenta en el diseo y dem
ostracin de propiedades (p.ej. invariantes) del bucle. No deben usarse 'break', '
continue' o 'return' para salir de un bucle.
Desafortunadamente, el cdigo del libro no sigue este principio.
La solucin idnea a este problema se muestra en el siguiente punto.
* Los arrays no tienen iteradores:
* for (Iterator<char> it = v.iterator(); n>0 && it.hasNext(); n--)
*
System.out.print(it.next() + " ");
Este cdigo tiene dos errores:
0. Los tipos base ('char') no se pueden pasar como parmetros genricos, tendra que u
sarse 'Character' y el autoboxing.
1. Los arrays no extienden 'Iterable<T>' y por tanto no tienen un mtodo 'iterator
'.
Hay que usar ndices (solucin idnea):
for (int i = 0; n > 0 && i < v.length(); i++, n--)
System.out.print(v[i] + " ");
* Ejemplos en PositionList.java y NodePositionList.java:
* NodePositionList<E> implementa el mtodo 'iterator' [Cdigo, lnea 160] y usa el ite
rador en los mtodos 'toString' [Cdigo, lnea 216] y 'forEachToString' [Cdigo, lnea 202
].
* Obsrvese que en el bucle 'for-each' de ste ltimo se lleva cuenta del nmero de elem
entos ya iterados en una variable auxiliar para poder determinar cundo concatenar
la coma, ya que no puede invocarse 'hasNext' dentro del bucle *Iteracin con bucl
e 'for-each' de Java.
* Ms ejemplos en *9.1.2 A Simple List-Based Map Implementation.
* EJERCICIO: Implementar la clase 'IterableArrayIndexList<E>' que implemente el
interfaz 'IndexList<E>' de IterableIndexList.zip (fichero disponible en el Aula
Virtual) y adems implemente los mtodos estticos 'toString' y 'forEachToString' simi
lares a los de 'PositionList<E>'.
* 6.3.4 List Iterators in Java
2.4 El estudio del caso peor nos da unos resultados ms precisos y con menor varia
bilidad que los estudios de casos medios y los experimentales. Los algoritmos ef
icientes en el caso peor lo sern tambin en los otros casos.
* En la prctica se necesita tanto el anlsis terico como el experimental: "In theory
there is no difference between theory and practice. In practice there is." (Yog
i Berra)
* En lo tocante a TADs en Java, las medidas de complejidad estn asociadas a los mt
odos de las clases (implementaciones), no a los interfaces. Un interfaz describe
simplemente la cabecera del mtodo (el qu) y no la implementacin (el cmo).
Un interfaz puede exigir que ciertos mtodos se implementen con una complejidad de
terminada, forzando as una representacin y familia de algoritmos para el TAD. Fina
lmente, la declaracin de los mtodos en los interfaces puede sugerir o descartar ci
ertas implementaciones.
* Notacin O()
* Intuicin: establecer la complejidad de una funcin del tamao de la entrada indican
do otra funcin proporcional que la acota asintticamente.
* Definicin Matemtica:
Sean f y g dos funciones de naturales a reales. Se dice que f(n) es del orden de
g(n), o f(n) es O(g(n)), si existe una constante real c>0 y una constante natur
al n0 >=1 tal que f(n) <= c*g(n) para n >= n0
* Intuicin: a partir de un valor n0 de la entrada, la funcin g(n) acota los valore
s de la funcin f(n) cuando n crece indefinidamente.
* Ejemplos [Transparencia 20].
* Definicin en Ingls: [Transparencias 21 y 30].
* Anlisis de complejidad: se calcula f(n) y se determina el "mnimo" g(n) [Transpar
encias 20-23] [Libro, p173, 'Characterizing Functions in Simplest Terms'].
* Se ignoran factores constantes y de orden inferior [Transparencias 20-23]. Per
o CUIDADO: [Libro, p176, 'Some Words of Caution']: "we should at least be somewh
at mindful of the constant factors and lower order terms we are "hiding"". Ejemp
lo: O(10100*n).
* Escala tpica de complejidad (de menor a mayor):
0. Constante: O(1)
1. Logartmica: O(log n)
2. Lineal: O(n)
3. N-Log-N: O(n log n)
4. Cuadrtica O(n2)
5. Cbica: O(n3)
6. Polinomial: O(nm)
7. Exponencial: O(2n) .. O(mn)
* Hay una relacin entre log2(x) y 2x.
Recordad: log2(x) = y <=> 2y = x.
Son funciones inversas:
* log2(2x) = x
* 2log2(x) = x
* Notaciones Omega y Theta
* [Transparencias 29-31] [Libro, p174]
* Complejidad: algunos comentarios y ejercicios
* Es realista que el coste de la evaluacin de expresiones y del indexado en arrays
sea constante? [Transparencia 11]. (El indexado de un array se hace en base a e
xpresiones y es asimismo una expresin.)
* Comparar [Transparencia 11] con la descripcin de 'Primitive Operations' en [Lib
ro, Seccin 4.2.2] y sealar las diferencias notables. Tendra sentido afirmar que la i
gualdad (==) de expresiones tiene complejidad constante? Cmo se implementa la igua
ldad de objetos en Java?
* La invocacin de mtodos no tiene complejidad constante, depende de la complejidad
del mtodo [Libro, Seccin 4.2.3, p170]: "except for method calls, of course".
* Preguntarse si el anlisis de algoritmos descritos en pseudocdigo es realmente un
anlisis terico de alto nivel. Cul es la semntica del pseudocdigo? No est el pseudoc
atado a un paradigma de programacin o modelo de computacin [Transparencia 8]? Se ha
cen suposiciones realistas sobre el coste de la recursin? Se ignora el potencial p
ara el paralelismo?
5 Arboles generales y binarios
* 7 Tree Structures
* Material
* Libro: Captulo 7.
* Transparencias: trees.pdf.
* Indicamos el cdigo en las subsecciones siguientes.
* 7.1 General Trees
* General Trees: Terminologa y Definiciones
* Motivacin: organizar informacin de forma jerrquica.
* Utilizados en la implementacin de otros TADs.
* La JCF no incluye una implementacin de rboles generales, se utilizan rboles en im
plementaciones de otros TADs (por ejemplo, Maps).
* Definicin recursiva [Libro, p281, ltimas tres lneas]:
Un rbol general es o bien vaco o bien un nodo raz que contiene un elemento y un con
junto de cero o ms (sub)rboles hijos. (Ntese que en un conjunto no hay orden ni rep
eticin).
* Definicin ms formal [CLRS'01, B.5], [AHU'83, p231]:
Un rbol libre ('free tree') es un grafo conectado, no-dirigido y acclico. Un rbol o
rdinario ('rooted tree') es un rbol libre en el que se elige un nodo como raz (se
orientan las aristas al representarlo grficamente).
* Terminologa [Transparencia 3]:
* Raz ('root'): nodo sin padre.
* Nodo interno ('internal node'): nodo con al menos un hijo.
* Nodo externo ('external node'): nodo sin hijos.
* Subrbol ('subtree'): nodo considerado como raz y todos sus descendientes.
ERRORES: La descripcin de ancestro y de descendiente en [Transparencia 3] es inco
mpleta.
* Terminologa que no est o que completa [Transparencia 3] y que est en el libro o e
n otras fuentes:
* Ancestro de un nodo v: un nodo w es ancenstro de v si v=w o w es ancestro del
padre de v [Libro, p282].
* Descendiente de un nodo w (la inversa de ancestro): v es descendiente de w si
w es ancestro de v [Libro, p282].
* Nodo hoja: nodo externo. Usaremos estos dos nombres indistintamente.
* Hermano ('sibling') de un nodo: nodo con el mismo padre.
* Arista ('edge') de un rbol: par de nodos en relacin padre-hijo o hijo-padre.
* Grado ('degree') de un nodo: el nmero de hijos del nodo.
Se puede extender sta definicin a todo el rbol: el grado de un rbol es el mximo de lo
s grados de todos sus nodos.
* Camino ('path') de un rbol: secuencia de nodos tal que cada nodo consecutivo fo
rma una arista. La longitud del camino es el nmero de aristas.
* rbol ordenado ('ordered tree'): existe un orden lineal (total) definido para lo
s hijos de cada nodo: primer hijo, segundo hijo, etc. Se visualiza dibujando los
hijos en orden de izquierda a derecha bajo el padre. Ejemplo: captulos de un lib
ro.
* Profundidad y altura de un nodo [Libro, '7.2.1 Depth and Height']:
* La profundidad de un nodo ('depth') es la longitud del camino desde ese nodo a
la raz (o viceversa). La longitud del camino es cero si el nodo es la raz. (El li
bro define la profundidad de un nodo de forma equivalente como el nmero de ancest
ros "propios" del nodo.)
* La altura de un nodo ('height') es la longitud del mayor de todos los caminos
del nodo a las hojas.
* Daremos definiciones de profundidad y altura mediante mtodos de Java en *7.2 Tr
ee Traversal Algorithms.
* Altura de un rbol no vaco: la altura de la raz.
* Profundidad y altura se han definido como propiedades de nodos. Por tanto, segn
estas definiciones no tiene sentido hablar de la profundidad o la altura de un r
bol vaco (sin nodos).
* La profundidad de un rbol podra definirse como la mayor de las profundidades de
las hojas, pero ese valor es igual a la altura. De hecho, la altura de un rbol ta
mbin se define como el mximo de la profundidad de todos sus nodos [CLR'90, p94].
* Nivel ('level'): conjunto de nodos con la misma profundidad. As, tenemos desde
el nivel 0 hasta el nivel 'h' donde 'h' es la altura del rbol.
* Interfaz Tree<E>
* Cdigo: Tree.java, InvalidPositionException, EmptyTreeException.java, BoundaryVi
olationException.java.
* Interfaz de rboles generales. El libro no muestra ni explica las interfaces y c
lases utilizadas en la implementacin del *Interfaz Tree<E>. Se centra ms en implem
entaciones de rboles binarios y derivados. Tampoco ofrece cdigo para TADs que util
izaran el interfaz de rboles generales, por ejemplo, *10.4 (2,4) Trees.
* Estudiamos este interfaz porque es la base del *Interfaz BinaryTree<E> de rbole
s binarios que son los que veremos en ms profundidad. No veremos implementaciones
de rboles generales en la asignatura.
* El *Interfaz Position<E> que se utilizaba en *6.2 Node Lists para abstraer la
implementacin de los nodos de una lista se usa en 'Tree<E>' para abstraer la impl
ementacin de los nodos de un rbol. De nuevo, una posicin se entiende de forma relat
iva en funcin de las posiciones vecinas (que sern los padres y los hijos).
* En el libro, el cdigo y las transparencias se usa la palabra nodo para referirs
e a una "posicin" ('Position<E>') no a la clase que la implemente. Nosotros tambin
seguimos esta convencin, si bien quedar claro por el contexto si por "nodo" nos r
eferimos a "nodos abstractos" (interfaz 'Position<E>') o a "nodos concretos" (al
guna implementacin de dicho interfaz).
* 'Tree<E>' es un interfaz pensado para trabajar directamente con posiciones (ab
stracciones de nodos). Los TADs de rboles suelen usarse en implementaciones de ot
ros TADs y para ello se necesita poder trabajar directamente (y eficientemente)
con nodos.
Esto explica que no es un interfaz recursivo, cuando s lo es la definicin de rbol g
eneral. Los mtodos trabajan con posiciones y no con rboles. Por ejemplo, se define
:
public Iterable<Position<E>> children(Position<E> v) throws ...
y no:
public Iterable<Tree<E>> children(Tree<E> t) throws ...
Por esta razn, los mtodos de las clases que usen el interfaz tomarn siempre un obje
to rbol como argumento para poder invocarle los mtodos del interfaz. Ejemplos en *
7.2 Tree Traversal Algorithms.
* El interfaz importa 'java.util.Iterator' y define el mtodo 'iterator' directame
nte, no extiende 'Iterable<E>'. Esto significa que un 'Tree<E>' no es un 'Iterab
le<E>'.
* El mtodo 'iterator' devuelve un iterador para iterar sobre todos los nodos del r
bol. En *7.2 Tree Traversal Algorithms veremos varias formas de recorrer los nod
os.
* Hay dos mtodos que devuelven 'Iterable<E>':
1. Mtodo 'positions', que es lo que hemos llamado 'elements' en *Cmo iterar sobre
TADs.
2. Mtodo 'children', que devuelve un iterable con los hijos del nodo. Si el rbol e
st ordenado el iterable estar ordenado segn el orden de los hijos.
* Algunos mtodos lanzan excepciones cuando los nodos no son vlidos:
* 'BoundaryViolationException' ser lanzada por 'parent' cuando el nodo argumento
sea la raz.
* 'EmptyTreeException' ser lanzada por 'root' cuando se invoque dicho mtodo sobre
un objeto rbol vaco.
* 'InvalidPositionException' lanzada por mtodos que toman posiciones como argumen
to cuando la posicin es invlida (p.ej., no es un objeto de una clase que implement
a nodos de un rbol binario).
* IMPORTANTE: El interfaz slo consta de mtodos observadores excepto un nico mtodo mo
dificador 'replace' que permite modificar el elemento almacenado en un nodo. Est
a decisin de diseo es deliberada [Libro, p284, ltimas lneas]: "we prefer to describe
different tree update methods in conjunction with specific applications of tree
s in subsequent chapters. In fact, we can imagine several kinds of tree update o
perations beyond those given in this book". Los mtodos modificadores se definirn e
n las clases que implementen aquellos interfaces, como *Interfaz BinaryTree<E>,
que extienden 'Tree<E>'.
* 7.2 Tree Traversal Algorithms
* Material
* [Transparencias 5-6, trees.pdf]
* Cdigo: Ejemplos que no son parte del paquete net.datastructures: http://highere
dbcs.wiley.com/legacy/college/goodrich/0470383267/student/ch07/ch07-fragments.ht
ml
En particular:
* Trees-depth
* Trees-height1
* Trees-height2
* Trees-preorderPrint
* Trees-parentheticRepresentation
* Trees-postorderPrint
* Trees-diskSpace
* Profundidad de un nodo
* public static <E> int depth(Tree<E> T, Position<E> v) {
* if (T.isRoot(v))
*
return 0;
* else
*
return 1 + depth(T, T.parent(v));
* }
* Explicamos por qu "static" y "<E>" en *Traversals: comentarios y ejercicio.
* Altura de un nodo (adaptado de Trees-height2)
* public static <E> int height(Tree<E> T, Position<E> v) {
* int h = 0;
* if (T.isExternal(v)) return h;
* else
*
for (Position<E> w : T.children(v))
*
h = Math.max(h, height(T, w));
* return 1 + h;
* }
* 7.2.2 Preorder Traversal
* [Transparencia 5]
* Cdigo: Trees-preorderPrint, Trees-parentheticRepresentation.
* public static <E> String toStringPreorder(Tree<E> T, Position<E> v) {
* String s = v.element().toString(); // the main "visit" action
* for (Position<E> w : T.children(v))
*
s += ", " + toStringPreorder(T, w);
* return s;
* }
* 7.2.3 Postorder Traversal
* [Transparencia 6]
* Cdigo: Trees-postorderPrint, Trees-diskSpace.
* public static <E> String toStringPostorder(Tree<E> T, Position<E> v) {
* String s = "";
* for (Position<E> w : T.children(v))
*
s += toStringPostorder(T, w) + " ";
* s += v.element(); // main "visit" action
* return s;
* }
* Traversals: comentarios y ejercicio
* Los mtodos que implementan los recorridos toman como parmetros el rbol y un nodo.
Hemos explicado las razones en *Interfaz Tree<E>.
* Los recorridos se implementan mediante mtodos genricos y estticos. Podemos asumir
que son mtodos de alguna clase esttica no genrica, por ejemplo:
* public static class Traversals {
* public static <E> int depth ...
* [Libro, p296], [CLRS'01, B.5] definen rbol binario lleno ('full binary tree') c
omo sinnimo de rbol propio. Otros ([AHU'83, p106], [Horowitz & Sahni "Data Structu
res in Pascal"]) lo definen como sinnimo de rbol binario perfecto.
* Definicin de rbol binario equilibrado ('balanced binary tree'): para todo nodo,
el valor absoluto de la diferencia de altura entre los dos subrboles hijos es com
o mximo 1.
Ms formalmente: para todo nodo 'n' con hijo izquierdo 'i' e hijo derecho 'd' se t
iene |h(i)-h(d)| <= 1.
En otras palabras: para todo nodo con altura 'h', o bien sus dos hijos tienen la
misma altura, h-1, o un hijo tiene altura h-1 y el otro h-2.
Obsrvese que segn la definicin, todo subrbol de un rbol equilibrado es equilibrado.
* Binary Trees: Algunos Usos
* [Transparencias 8-9]
* Otros usos: implementacin de TADs que veremos en los siguientes temas.
* 7.3.3 Properties of Binary Trees
* [Transparencia 10]
* Algunas propiedades se deducen de otras, por ejemplo:
n = e + i
<=> { e = i + 1 <=> i = e - 1 }
n = e + (e - 1)
<=> { aritmtica }
n = 2e - 1
* Otro ejemplo (propiedad que no est en [Transparencia 10]):
n = e + i
<=> { e = i + 1 }
n = (i + 1) + i
<=> { aritmtica }
n = 2i + 1
* Interfaces y clases de la implementacin de BinaryTree<E>
* Diagrama de clases
* Interfaz Tree<E>
*
^
*
| E
*
|
* Interfaz BinaryTree<E> ------ U ----> Interfaz Position<E>
*
^
/
^
*
|
/
| E
*
|
/
|
*
| I
/---- U ----> Interfaz BTPosition<E>
*
|
/
^
*
|
/
| I
*
|
/
|
* Clase LinkedBinaryTree<E> ----- U ----> Clase BTNode<E>
*
* U: Usa. I: Implementa. E: Extiende.
* Omitimos las clases de excepciones.
* Cuestiones de implementacin de rboles binarios
* Representacin de nodos: [Transparencia 17, trees.pdf] [Libro, p301, '7.3.4 A Li
nked Structure for Binary Trees'].
* Un nodo tiene referencias al padre, al elemento, al hijo izquierdo y al hijo d
erecho.
* En general se sigue la siguiente convencin en las figuras de rboles del libro y
las transparencias: se dibujan los nodos internos como crculos y los externos com
o cuadrados.
* Interfaz BinaryTree<E>
* Cdigo: BinaryTree.java.
* Extiende 'Tree<E>' con mtodos "getters" e interrogadores para nodos hijos que p
ueden lanzar excepciones. Los mtodos 'left' y 'right' lanzan 'BoundaryViolationEx
ception' si el nodo 'v' no tiene, respectivamente, hijo izquierdo o hijo derecho
. Los mtodos lanzan 'InvalidPositionException' si el nodo 'v' no es vlido.
t'.
* Los mtodos 'iterator', 'positions' y 'children' devuelven como iterable un una
lista de posiciones *Clase NodePositionList<E>. La lista es vaca si el rbol es vaco
. La iteracin es un recorrido en preorden implementada por el mtodo protegido 'pre
orderPositions' [Cdigo, lnea 295]. El mtodo 'positions' devuelve la lista de nodos
en preorden y el mtodo 'iterator' recorre la lista de nodos devuelta por 'positio
ns' y crea una nueva lista con los elementos almacenados en los nodos. El mtodo '
children' devuelve una lista con los nodos hijos del nodo que toma como parmetro.
Si dicho nodo no tiene hijos la lista es vaca.
* Se definen mtodos modificadores que no estn en el *Interfaz BinaryTree<E>:
* Descritos en [Libro, p303]: 'addRoot', 'remove', 'attach', 'insertLeft' e 'ins
ertRight'.
Importante: Estos mtodos debemos estudiarlos pues son los que nos permiten, junto
con el constructor de la clase, el poder crear rboles binarios. Ejemplos en *Con
struccin de rboles binarios.
Recordamos que el *Interfaz BinaryTree<E> extiende el *Interfaz Tree<E> el cual
slo declara un mtodo modificador: 'replace'.
* No descritos en el libro: 'swapElements', 'expandExternal', 'removeAboveExtern
al', 'sibling', etc. Estos mtodos no necesitamos estudiarlos, pero es interesante
entender su cdigo. Estos mtodos se ofrecen porque los usarn clases que extienden '
LinkedBinaryTree<E>', como por ejemplo, *10.1 Binary Search Trees.
* Se define un mtodo 'createNode' [Cdigo, lnea 290] que devuelve un objeto creado p
or el constructor de 'BTNode<E>'. El mtodo 'createNode' es invocado por los mtodos
modificadores 'addRoot', 'insertLeft' e 'insertRight'.
Puede observarse que la construccin de nodos (objetos de clase 'BTNode<E>') en la
clase 'LinkedBinaryTree<E>' solamente se hace invocando 'createNode'.
Esto se hace as porque en el libro se definen clases que extienden 'LinkedBinaryT
ree' y sobrescriben ('override') 'createNode'. En Java los constructores de clas
e no pueden sobrescribirse. Por ello se usa un mtodo ordinario, que puede sobresc
ribirse, para construir nodos.
* Se definen los mtodos 'preorderPositions' e 'inorderPositions' que aaden los nod
os del rbol, recorridos en preorden y en inorden respectivamente, al final de una
lista de posiciones (nodos) que toman como argumento.
* Construccin de rboles binarios
* La construccin de un rbol binario se puede hacer de varias maneras despus de llam
ar al constructor mediante combinaciones de 'addRoot', 'insertLeft', 'insertRigh
t', 'attach', 'expandExternal', etc.
*
1
*
/ \
* 2 3
* / \ \
* 4 5 6
Construccin 1:
LinkedBinaryTree<Integer> tree = new LinkedBinaryTree<Integer>();
tree.insertLeft(tree.insertLeft(tree.addRoot(1),2),4);
tree.insertRight(tree.left(tree.root()),5);
tree.insertRight(tree.insertRight(tree.root(),3),6);
Construccin 2:
LinkedBinaryTree<Integer> tree = new LinkedBinaryTree<Integer>();
tree.addRoot(1);
tree.expandExternal(tree.root(),2,3);
tree.expandExternal(tree.left(tree.root()),4,5);
tree.insertRight(tree.right(tree.root()),6);
* En ambos casos el objeto 'tree' es de clase 'LinkedBinaryTree<E>' y no de tipo
'BinaryTree<E>' porque ste ltimo interfaz no ofrece los mtodos modificadores que s
e invocan sobre el objeto 'tree'. Recordatorio de Java:
* class Padre {}
* class Hija extends Padre {
* public void m() {}
* }
* class Main {
* public void test() {
*
Padre p = new Hija();
*
p.m(); /* Error de compilacin: "cannot find symbol" */
* }
* }
* class Padre {
* public void m() {}
* }
* class Hija extends Padre {
* public void m() {}
* }
* class Main {
* public void test() {
*
Padre p = new Hija();
*
p.m(); /* Enlazado dinmico: se invoca el mtodo 'm'
*
* de la clase 'Hija'. */
* }
* }
* 7.3.6 Traversals of Binary Trees
* En preorden y en postorden. Se implementan usando los mtodos 'root', 'left' y '
right', que devuelven respectivamente los nodos raz y los nodos hijo izquierdo y
derecho.
* Inorden [Transparencia 12] [Cdigo, LinkedBinaryTree.java, lnea 306].
* EJERCICIO: Implementar 'postorderPositions' (que falta en el cdigo de LinkedBin
aryTree.java).
* Ejemplos de uso: mostrar y evaluar expresiones aritmticas. [Transparencias 13-1
4], [Libro, p312-316, junto con otros ejemplos].
* Recorrido Euler: [Transparencia 15 y 19-20], [Libro, p317-322]. No lo veremos
en clase.
* Complejidad de los mtodos
* [Libro, pgina 309]
* Para la implementacin LinkedBinaryTree.java.
size,
Complejidad
Mtodo
iterator,
root,
replace
O(n)
hasLeft,
*insertLeft,
O(1)
La complejidad
isEmpty
parent,
hasRight,
positions
insertRight,
children,
constante
isInternal,
left,
attach,
se consigue
right,
isExternal,
remove
sibling
porque
isRoot
los parmetros y valores devueltos p
or los mtodos son nodos del rbol.
6 Colas con prioridad, montculos y ordenacin
* 8 Priority Queues
* Material
* Libro: Captulo 8.
* Transparencias: priorityqueues.pdf.
* Cdigo Libro:
* Interfaces: Entry.java, PriorityQueue.java.
* Clases: DefaultComparator.java, EmptyPriorityQueueException.java, InvalidKeyEx
ception.java, SortedListPriorityQueue.java.
* Cdigo Java Platform :
* Interfaces: java.util.Comparator<T> y java.lang.Comparable<T>.
* Motivacin de las colas con prioridad
* En los TADs que hemos visto hasta ahora el lugar que ocupa un elemento en la i
mplementacin del TAD es independiente de cualquier propiedad del elemento.
* En las colas con prioridad la posicin que ocupa un elemento dentro de la cola v
iene determinada por la prioridad del elemento. Ejemplos:
* Cola del supermercado en la que tiene preferencia algn colectivo.
* Llegadas a urgencias en un hospital.
* La prioridad de un elemento viene dada por un valor diferente del propio eleme
nto que llamaremos clave ('key'). En adelante llamaremos al elemento valor ('val
ue'). La asociacin de una clave a un valor, o par "clave-valor", lo llamaremos en
trada ('entry').
* Convencin: la clave establece la prioridad inversamente, cuanto menor sea la cl
ave mayor la prioridad.
* Las colas con prioridad son TADs que almacenan entradas y ofrecen un mtodo que
* Interfaz Entry<K,V>
* Cdigo: Entry.java.
* [Transparencia 4]
* "Composition pattern".
* La clase representa un producto cartesiano con "getters".
* Un objeto de la clase representa un par del producto cartesiano.
* Interfaces Comparable<T> y Comparator<T>
* [Transparencias 5-6]
* Ambos interfaces se utilizan para definir rdenes totales. La diferencia est en cm
o y para qu se usan.
* Interfaz 'java.lang.Comparable<T>':
* public interface Comparable<T> {
* public int compareTo(T t);
* }
* Interfaz 'java.util.Comparator<T>':
* public interface Comparator<T> {
*
public int
compare(T t1, T t2);
*
public boolean equals(Object o); // Igualdad de comparadores
* }
* Debeis leer con detalle las descipciones de la API:
* http://download.oracle.com/javase/6/docs/api/index.html?java/lang/Comparable.h
tml
* http://download.oracle.com/javase/6/docs/api/index.html?java/util/Comparator.h
tml
* Ideas claves:
* La nocin de orden natural de 'Comparable<T>':
La implementacin de 'Comparable<T>' por la clase 'T' hace que sta tenga que implem
entar el mtodo 'compareTo' para comparar dos objetos de 'T'. Ese mtodo de comparac
in queda fijo para todos los objetos de 'T' y se le llama orden natural.
Dados 't1' y 't2' objetos de 'T', la invocacin t1.compareTo(t2) debe devolver un
entero 'i' tal que:
* i < 0 si t1 es menor que t2.
* i == 0 si t1 es igual que t2.
* i > 0 si t2 es menor que t1.
El orden natural es consistente con equals cuando se cumple: 't1.compareTo(t2) =
= 0' si y slo si 't1.equals(t2)'.
Ejemplo: la clase 'String' de Java implementa 'Comparable<String>' y por tanto i
mplementa el mtodo 'compareTo' que se puede usar para comparar cadenas de caracte
res. El mtodo de comparacin elegido computa el orden lexicogrfico de las cadenas.
public class String implements Comparable<String> {
public int compareTo(String s) {
/* Comparacin lexicogrfica entre la cadena de este objeto y la
* cadena 's' pasada como argumento
*/
...
}
}
Ejemplo de uso:
public static void main(String [] s) {
String s1 = "Terabyte"; /* 10^12 bytes. */
String s2 = "Terapeuta"; /* 10^12 peutas. */
int r = s1.compareTo(s2);
if (r < 0)
System.out.println(s1 + " es menor que " + s2);
else if (r == 0)
System.out.println(s1 + " es igual que " + s2);
else
System.out.println(s1 + " es mayor que " + s2);
}
Slo hay una forma de comparar cadenas que es mediante el mtodo 'compareTo'. Para p
oder comparar cadenas de otra forma habra que reescribir el cdigo de 'compareTo' y
recompilar.
* La nocin de objeto funcin de 'Comparator<T>':
Los objetos de aquellas clases que implementen el interfaz 'Comparator<T>' imple
mentan un mtodo de comparacin 'compare' para objetos de la clase 'T'.
Dados 't1' y 't2' objetos de 'T' y 'c' un objeto comparador, la invocacin c.compa
re(o1,o2) debe devolver un entero 'i' tal que:
* i < 0 si t1 es menor que t2.
* i == 0 si t1 es igual que t2.
* i > 0 si t2 es menor que t1.
El comparador es consistente con equals cuando se cumple: 'c.compare(t1,t2) == 0
' si y slo si 't1.equals(t2)'. El mtodo 'equals' debe ser simtrico: la expresin 't1.
equals(t2) == t2.equals(t1)' debe ser cierta.
Se pueden usar diferentes objetos comparadores para comparar objetos de clase 'T
'. Ejemplo: podemos definir varios comparadores para la clase 'String': comparad
or lexicogrfico, tamao, coste de compresin bajo zip, etc:
public class SizeStringComparator implements Comparator<String> {
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
public boolean equals() { ... }
}
public class LexicographicStringComparator implements Comparator<String> {
public int compare(String s1, String s2) {
int minLength = Math.min(s1.length(),s2.length());
int eq = 0;
for (int i = 0; i < minLength && eq == 0; i++)
eq = s1.charAt(i).compareTo(s2.charAt(i)); // compareTo de Character
if (eq != 0)
return eq;
else {
eq = s1.length() - s2.length();
return eq;
}
}
public boolean equals() { ... }
}
El mtodo 'equals' determina la igualdad entre comparadores, no entre objetos de c
lase 'T'. Se invocara como c1.equals(c2) donde 'c1' y 'c2' son objetos de clase '
Comparator<T>' para alguna clase 'T'.
Ejemplo de uso:
public static void main(String [] s) {
String s1 = "Terabyte";
String s2 = "Terapeuta";
SizComp sc = new SizeStringComparator();
LexComp lc = new LexicographicStringComparator();
int r;
r = lc.compare(s1,s2);
if (r < 0)
System.out.println(s1 + " es menor que " + s2);
else if (r == 0)
System.out.println(s1 + " es igual que " + s2);
else
System.out.println(s1 + " es mayor que " + s2);
r = sc.compare(s1,s2);
if (r < 0)
System.out.println(s1 + " es menor que " + s2);
else if (r == 0)
System.out.println(s1 + " es igual que " + s2);
else
System.out.println(s1 + " es mayor que " + s2);
}
* ERRORES: El ejemplo en [Transparencia 6] no usa genricos. Debera ser como se mue
stra a continuacin:
* public class Lexicographic implements Comparator<Point2D> {
* private int xa, ya, xb, yb;
* public int compare(Point2D a, Point2D b) {
*
xa = a.getX();
*
ya = a.getY();
*
xb = b.getX();
*
yb = b.getY();
*
if (xa != xb) return (xb - xa);
*
else
return (yb - ya);
* }
* // tambin debe implementarse el mtodo 'equals'.
* }
* Interfaz PriorityQueue<K,V>
* Cdigo: PriorityQueue.java, InvalidKeyException.java, EmptyPriorityQueueExceptio
n.java.
* Los mtodos 'insert', 'min' y 'removeMin' devuelven objetos de clase 'Entry<K,V>
'. El mtodo 'insert' devuelve el objeto 'Entry<K,V>' insertado en la cola.
* Excepciones:
* 'EmptyPriorityQueueException.java' lanzada cuando se intenta obtener o borrar
el valor de clave mnima en una cola vaca.
* 'InvalidKeyException.java' lanzada si la clave no es vlida (en teora, cuando no
tiene igualdad o orden total definido para ella).
* Colas con prioridad: ejemplo de uso
* Los programas que usan colas con prioridad:
* Definirn interfaces o clases para claves y valores.
* Crearn objetos claves y valores.
* Podrn definir varios comparadores para claves.
* Construirn una o varias colas.
* Invocarn los mtodos de la cola segn la aplicacin.
* Ejemplo:
* public static void main(String args[]) {
*
* PriorityQueue<Integer,String> cola
*
= new SortedListPriorityQueue<Integer,String>();
*
* Alumno<String> alumno = new Alumno<String>("Alumno de la FIM");
*
* cola.insert(1, "Programacin II");
* cola.insert(4, "Redes");
* cola.insert(3, "Bases");
* cola.insert(0, "AED");
*
* while (cola.size() > 0) {
*
alumno.estudiar(cola.min());
*
cola.removeMin();
* }
* }
* EJERCICIO: Se podran mostrar los valores en la cola sin tener que invocar 'remov
eMin'?
* EJERCICIO: Tendra sentido definir un iterador para colas con prioridad? En caso
positivo, implementarlo para 'SortedListPriorityQueue<K,V>' y reescribir el ejem
plo de cdigo anterior para que use el iterador.