You are on page 1of 37

Algoritmos y Estructura de Datos

GUIN DE CLASES DE TEORA


Pablo Nogueira
Actualizado: 14 de noviembre 2011, 13:03
Este fichero es un guin que se complementa en clase con transparencias, explicaci
ones en la pizarra y discusiones.
ndice
* 1 Normativa y material
* 2 Repaso de listas simplemente enlazadas
* 3 Listas indexadas, enlazadas y secuencias
* 4 Conjuntos, iteradores, complejidad
* 5 Arboles generales y binarios
* 6 Colas con prioridad, montculos y ordenacin
1 Normativa y material
* Preliminares
* La Gua de Aprendizaje est disponible en:
1. Aula Virtual (Gua en formato HTML) <- recomendado
2. Web facultad (Gua en formato PDF):
* GII: http://www.fi.upm.es/?pagina=1325
* GMI: http://www.fi.upm.es/?pagina=1333
La asignatura es comn al GII y al GMI: se imparte con las mismas normas y conteni
dos.
* Fechas importantes
Entrega
Semana
Examen
Final
18
Extr.
*16
Material
de julio
enero
251prctica
10
314
(por
(por
dedela
confirmar)
confirmar)
2012,
2011,
asignatura
15:00
10:00
* Libro de la asignatura:
M. T. Goodrich y R. Tamassia, "Data Structures and Algorithms in Java", Wiley, 5
a edicin.
* Material en lnea asociado al libro:
* http://net3.datastructures.net/download.html (Cdigo).
* http://net3.datastructures.net/doc5/index.html (Javadoc).
* http://ww0.java5.datastructures.net/ (Cdigo, Ejemplos, Transparencias).
* Bibliografa complementaria recomendada y ocasionalmente citada en este guin:
* [JLS'3E] Java Language Specification, 3rd Edition, http://java.sun.com/docs/bo
oks/jls.
* [JPSE6] Java Platform SE 6, incluye Java Collections Framework (JCF), http://d
ownload.oracle.com/javase/6/docs/api/index.html.
* [CLRS'01] Thomas Cormen, Charles Leiserson, Ronald Rivest, Clifford Stein, "In
troduction to Algorithms", 2nd Edition, MIT Press. (Hay una tercera edicin.)
* [JP'05] Peter Sestoft, "Java Precisely", 2ed, MIT Press.
* [ALT'03] Moshe Augenstein, Yedidyah Langsam, Aaron M. Tenenbaum, "Data Structu
res Using Java", Prentice Hall.
* [AHU'83] Alfred Aho, John Hopcroft, Jeffrey Ullman, "Data Structures and Algor
ithms", Addison-Wesley. (Un clsico de los 80)
2 Repaso de listas simplemente enlazadas
* Motivacin
* Revisaremos el concepto de estructura de datos (llamado histricamente 'Tipo Abs
tracto de Datos' o TAD), que ya ha sido introducido en la asignatura Programacin
II.
* Estudiaremos un TAD de listas inspirado en los estudiados en la asignatura Pro
gramacin II, en concreto la implementacin mediante cadenas simplemente enlazadas (
'singly-linked').
* Repasaremos los conceptos de Java involucrados en el cdigo de dicho TAD.
* Material
* Libro (lecturas recomendables):
* Captulo 1 'Java Programming Basics'.
* Captulo 2 'Objetct-Oriented Design'.
* Captulo 3 'Arrays, Linked Lists, and Recursion' (contiene un TAD de listas que
es una variacin de los que veremos en la asignatura).
* Cdigo: 'ListasTemaI.zip' disponible en el Aula Virtual, contiene:
* ExampleUse.java

* 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

amente segn las necesidades del programa.


* En la prctica, el tamao de la lista est acotado por la memoria disponible de la c
omputadora.
* Diagrama de clases de listLibrary
*
Clase EmptyListException
* Interfaz List<E> -------- U ---------> Clase IndexOutOfBoundsException
*
^
/
*
|
/
*
I |
/
*
|
/
* Clase SinglyLinkedList<E> ---- U ----> Clase Node<E>
*
* U: Usa. I: Implementa.
* Interfaz List<E>
* Cdigo: listLibrary/List.java.
* El interfaz describe la funcionalidad: contiene las declaraciones de los mtodos
a los que responder un objeto de una clase que implemente el interfaz.
* El comportamiento se especifica en comentarios (pobreza de Java).
* Estudiamos en clase los mtodos del interfaz uno por uno, excepto los mtodos 'ele
ments' e 'iterator' que veremos en *6.3 Iterators.
* No hemos considerado la clonacin (mtodo 'clone') ni la igualdad (mtodo 'equals')
de listas.
* Asumiremos copias superficiales ('shallow copy') en construccin e insercin. Por
ejemplo, el mtodo 'addFirst' insertar el objeto elemento en la lista, no una copia
('clone') del mismo.
* Los mtodos tratan con elementos y/o con posiciones (ndices).
* Definicin de ndice: el ndice de un elemento es el nmero de elementos en la lista q
ue estan antes. El primer elemento tiene ndice 0 y el ltimo tiene ndice 'size() - 1
', donde 'size()' es el nmero de elementos (tamao) de la lista.
* Algebra no libre: se cumplen ecuaciones condicionales que involucran a las ope
raciones de construccin. Dichas ecuaciones son las que verdaderamente especificara
n el comportamiento (la funcionalidad) de la lista.
Un lgebra consiste en un conjunto de valores (todos los objetos lista posibles),
un conjunto de operaciones (mtodos), y un conjunto de leyes (ecuaciones condicion
ales). Ejemplo de ecuacin condicional donde 'l' es un objeto de una clase que imp
lementa el interfaz y 'e' un elemento arbitrario:
Si 'l.isEmpty()' entonces 'l.last(l.addFirst(e))' es igual a 'e'.
* Conceptos Java involucrados (y que deben repasarse):
* Importacin de paquetes.
* Interfaces.
* Genricos.
* Mtodos.
* Excepciones ('checked' y 'unchecked').
* Clase EmptyListException
* Cdigo: listLibrary/EmptyListException.java.
* Tomado del paquete net.datastructures.
* Ejemplo de clase que implementa una excepcin en tiempo de ejecucin. Hereda de la
clase estndar de Java 'RuntimeException'.
* Ser lanzada por aquellos mtodos que no pueden ser invocados sobre listas vacas.
* Clase Node<E>
* Cdigo: listLibrary/Node.java.
* Implementa los nodos que se enlazarn.
* Se asume 'null' como centinela (sealar el final de la cadena enlazada).
* Mostramos ejemplos de cadenas enlazadas en la pizarra.
* Conceptos de programacin Java involucrados:
* Genricos.
* Atributos de clase (tambin llamadas "variables de instancia").
* Constructores.
* Sobrecarga: nombres compartidos de atributos y mtodos (p.ej., 'element').
* Modificadores de visibilidad ('public', 'private').

* Mtodos "getters" y "setters".


* Variable 'this'.
* Declaracin, construccin, variables y objetos:
* Declaracin y construccin:
* Node<Char> n ;
/* Por qu no Node<char>? */
* ...
* n = new Node<Char>('A',null) ;
* Declaracin e inicializacin:
* Node<Char> n = new Node<Char>('A',null) ;
* La variable 'n' es una referencia a un objeto de la clase 'Node':
* variable
objeto
*
n -------> |------|
*
| 'A' |
*
|------|
*
| null |
*
|------|
El siguiente cdigo no es necesariamente incorrecto, depende del contexto:
Node<Char> n = new Node<Char>('A',null) ;
n = new Node<Char>('B',null);
/* Objeto nodo muerto recolectado por el recolector de basura */
* Clases envoltorio (ej, 'Char') para tipos primitivos ('char') y sus conversion
es automticas. En Ingls, 'wrapper class' y 'autoboxing'.
* Clase SinglyLinkedList<E>
* Cdigo: listLibrary/SinglyLinkedList.java.
* La implementacin detalla la estructura (atributos) y los algoritmos (comportami
ento) que realizan la funcionalidad tal y como se pide en la especificacin (los c
omentarios en el caso de Java; las ecuaciones condicionales si hubieran podido s
er especificadas).
* Estudiamos en clase los mtodos de la clase as como ejemplos de funcionamiento. C
onstruimos en la pizarra el cdigo de los mtodos 'first', 'addLast', 'get' y 'remov
e'.
* Conceptos de programacin Java involucrados: variables y referencias, objetos, e
xpresiones, condicionales, bucles, excepciones, bloques 'try-catch', declaracion
es locales, comprobacin de valores frontera, etc.
* EJERCICIO: Realizar los ejercicios indicados en el cdigo.
* EJERCICIO: Aadir al *Interfaz List<E> el siguiente mtodo e implementarlo en la *
Clase SinglyLinkedList<E>:
* public void append(List<E> list)
El mtodo debe concatenar los elementos de la lista argumento 'list' al final de l
a lista.
* Ejemplo de uso
* Cdigo: ExampleUse.java.
* Ejemplo de uso de listas. Lo estudiamos y ejecutamos en clase.
* Anlisis de la librera propuesta
* El *Interfaz List<E> contiene mtodos que manipulan elementos y posiciones de la
lista (indicados mediante ndices enteros).
* La *Clase Node<E> y la *Clase SinglyLinkedList<E> se utilizan en la implementa
cin.
* Anlisis:
1. El usuario del interfaz no conoce ni necesita conocer la implementacin. Los no
dos no se manipulan directamente, estn ocultos (encapsulados).
2. El acceso mediante ndices no es eficiente: los mtodos recorren secuencialmente
la lista desde la cabeza ('head') hasta la posicin deseada usando el mtodo 'getNex
t' de los nodos.
La complejidad de dichos mtodos en el caso peor es lineal. Formalmente, la comple
jidad de 'get', 'set' y 'remove' es O(n) donde n es el tamao de la lista. (Nos co
ntentamos de momento con una definicin informal de complejidad. La estudiaremos e
n detalle en *4.2 Analysis of Algorithms.)
La modificacin de la lista mediante la manipulacin directa de nodos sera eficiente,
pero los nodos estn (y deben estar) ocultos.

3. No hay un mtodo para insertar un elemento en una posicin arbitraria de la lista


, slo se puede insertar por el principio o por el final.
4. EJERCICIO: Implementar los siguientes mtodos:
5. public void add(int i, E e) throws IndexOutOfBoundsException;
6.
7. public List<E> tail() throws EmptyListException, IndexOutOfBoundsException;
8.
9. public List<E> take(int n) ;
El primer mtodo debe insertar un elemento en la posicin 'i' tal que '0 <= i' e 'i
<= size()', lanzando la excepcin en caso contrario.
EJERCICIO: Por qu se admite 'i == size()'?
El segundo mtodo debe devolver la cola de la lista si la lista no es vaca o lanzar
la excepcin si la lista es vaca.
El tercer mtodo debe devolver una nueva lista con los 'n' primeros elementos.
Problemas que encontrareis:
* La insercin mediante ndices tampoco es eficiente.
* En los ltimos dos mtodos, el valor devuelto es una lista. Si los mtodos devolvies
en nodos en vez de listas su implementacin sera sencilla.
* En *Listas indexadas, enlazadas y secuencias veremos dos TADs de listas:
* Uno que ofrece mtodos que utilizan ndices y estn implementados ms eficientemente:
*6.1 Array Lists.
* Otro que ofrece mtodos que utilizan nodos pero sin revelar la implementacin de l
os mismos: *6.2 Node Lists.
Finalmente veremos un TAD que integra la funcionalidad de ambas alternativas: *6
.4.2 Sequences.
* Supuestas ventajas de la abstraccin de datos
* Idealmente, la independencia de la representacin (de la implementacin) implica b
ajo acoplamiento: se puede cambiar la implementacin sin afectar el cdigo cliente q
ue usa los mtodos del TAD. El interfaz sirve de "contrato" entre el cliente y el
implementador del TAD.
Ejemplo: En vez de cadenas enlazadas podramos haber implementado las listas usand
o vectores ('arrays') de Java *6.1 Array Lists.
* Idealmente, los TADs tienen alta cohesin, bajo acoplamiento, y encajan con el d
iseo modular y el refinamiento progresivo (se pueden posponer decisiones de imple
mentacin durante el proceso de diseo).
* En la prctica, hay factores pragmticos como la eficiencia que pueden requerir un
cambio de implementacin que afecta al interfaz o incluso requerir la sustitucin d
e un TAD por otro. El software evoluciona.
Ejemplo: lo discutido en *Anlisis de la librera propuesta.
* Hay mtodos estadsticos y probabilsticos para la eleccin de la implementacin adecuad
a de un TAD basndose en anlisis de los mtodos utilizados.
3 Listas indexadas, enlazadas y secuencias
* 6.1 Array Lists
* Material
* Libro: Seccin 6.1.
* Transparencias: arraylists.pdf (indicamos en este guin cules utilizamos).
* Cdigo:
* IndexList.java (interfaz), ArrayIndexList.java (clase).
* Genericarraycreation.zip (cdigo explicativo sobre vectores genricos).
* ERRORES:
* Transparencias y libro: el texto llama 'Array List' al TAD pero el nombre del
interfaz Java es 'IndexList'. Tiene ms sentido que as se llame el TAD ya que el us
o de arrays es una cuestin de implementacin.
* [Transparencia 2]:
* El TAD no 'extiende' la nocin de array: la abstrae y generaliza.
* Los ndices no tienen tipo 'integer' sino 'int'.
* EJERCICIO: Sera mejor tener 'Integer'?
* La clase de los elementos no es 'Object' sino 'E'.
* Motivacin de listas indexadas
* Abstraccin y eficiencia:

* En *Listas simplemente enlazadas y *Anlisis de la librera propuesta vimos un TAD


de listas con mtodos de bsqueda y modificacin que utilizan ndices. Sin embargo la i
mplementacin de esos mtodos mediante cadenas enlazadas no es eficiente (coste line
al).
* Una forma eficiente de acceder a la lista mediante ndices es utilizar vectores
('arrays'). Tenemos vectores en Java, pero tienen longitud finita. Necesitamos u
n TAD que abstraiga la nocin de vector en una estructura cuyo tamao pueda crecer (
y decrecer tambin).
* Las listas indexadas (array lists) son listas donde todos los mtodos de acceso
y modificacin utilizan ndices.
* La implementacin natural que veremos utilizar un vector de Java para lograr un a
cceso eficiente.
* Definiciones, notacin y propiedades:
* Tamao del vector interno (o capacidad de la lista): N.
* Nmero de elementos almacenados (o tamao de la lista): n.
* Los elementos se almacenan en posiciones 0 a n-1 de un vector sin huecos vacos
entre elementos.
* Dos definiciones de rango:
* Rango ('range') : el intervalo de 0 a n-1.
* Rango ('rank') : un elemento en el ndice i est en el rank i+1.
* Dficit ('underflow'):
Cuando n cae por debajo de una cota, por ejemplo, n < N/4 podemos utilizar un ve
ctor interno ms pequeo.
* Desbordamiento ('overflow'):
Cuando n=N, no podemos aadir ms elementos al vector. Podemos utilizar un vector in
terno ms grande.
Estrategias [Transparencia 8]:
1. Incremental ('incremental strategy'): usar un vector interno de un tamao mayor
que el anterior en un valor constante: N = N + c.
2. Duplicacin ('doubling strategy'): usar un vector interno de un tamao el doble d
el actual: N = 2 * N.
Hablaremos de sus costes en *Complejidad y costes amortizados.
* Diagrama de clases
* Interfaz IndexList<E> -------- U ---------> ClasIndexOutOfBoundsException
*
^
^
*
I |
|
* Clase ArrayIndexList<E> ------ U ----------------------/
*
* U: Usa. I: Implementa.
* Interfaz IndexList<E>
* Los mtodos del interfaz usan la variable 'i' para ndices:
* Indices para 'get', 'set', y 'remove' entre 0 y n-1 inclusive.
* Indice para 'add' entre 0 y n inclusive. Por qu?
* Se lanza excepcin 'IndexOutOfBoundsException' si el valor del ndice pasado no es
t dentro del rango que espera el mtodo.
* Los mtodos 'set' y 'remove' devuelven un elemento. Motivo: composicin de invocac
iones.
* ERRORES: IndexList.java importa el interfaz 'java.util.Iterator' pero no se de
clara un mtodo 'iterator' que devuelva un iterador y tampoco se extiende del inte
rfaz Iterable<E> *6.3 Iterators.
* [Libro, Seccin 6.1.2 'The Adapter Pattern', p235]: esta seccin explica que Index
List<E> se puede adaptar (patrn de diseo "Adapter") para definir el interfaz Deque
<E> que no veremos aqu.
* Clase ArrayIndexList<E>
* Los mtodos de la clase usan la variable 'r' para ndices. (Los mtodos del interfaz
usaban la variable 'i'). No se usan ranks.
* Atributos:
vector
'A'
Descripcin
Variable
'capacity'
el
*'size'
Vemos
tamao
nmero
Java
elde
del
cdigo
deelementos
vector
elementos
de los
(que
(que
dehemos
mtodos
tipollamado
hemos
Ellamado
en
clase.
N)n)
* Vectores genricos [Cdigo, lneas 16 (constructor) y 48 ('add')]. Conceptos Java in
volcucrados:

1. No se pueden crear vectores genricos debido a la implementacin de genricos media


nte 'type erasure' [Libro, p90] [JP'95, p90].
2. Variable polimrfica y downcasting.
3. El compilador da una advertencia ('warning').
ERRORES: Realmente no es la forma correcta de crear vectores genricos. Se deben u
sar los mtodos 'getClass' y 'Array.newInstance' del paquete de reflexin 'java.lang
.reflect.*' (como se ha visto en Programacin II).
http://download.oracle.com/javase/6/docs/api/java/lang/reflect/Array.html#newIns
tance%28java.lang.Class,%20int%29
Ver cdigo demostrativo en Genericarraycreation.zip.
Desafortunadamente la librera net.datastructures no usa reflexin.
* El mtodo 'size' devuelve el valor del atributo 'size' (sobrecarga).
* Se usa mtodo protegido (protected) 'checkIndex' para comprobar que los ndices es
tn en rango y lanzar 'IndexOutOfBoundsException' en caso contrario. Obviamente, '
r > n-1' es lo mismo que 'r >= n'.
* Los mtodos 'add' y 'remove' pueden tener que desplazar elementos ('shifting') d
el vector hacia la derecha o hacia la izquierda respectivamente. [Transparencias
5 y 6] [Cdigo, lneas 53 y 63].
* Los bucles que realizan los desplazamientos siguen el mismo patrn:
* for ( int i = START ; COND(i,END) ; MODIF(i) )
* SWAP
Obsrvese la dualidad en los bucles entre los valores START, END, el predicado de
condicin COND, la modificacin del ndice MODIF y el intercambio de valores SWAP.
* El mtodo 'add' aumenta la capacidad a 2*N (estrategia de duplicacin) *Motivacin d
e listas indexadas cuando el vector est lleno. Realmente lo que hace es copiar el
ementos a un nuevo vector de doble tamao y hacer que el atributo 'A' referencie e
l nuevo vector. El recolector de basura recuperar la memoria del antiguo vector.
[Cdigo, lineas 46-52].
* El cdigo de 'add' tiene dos bucles 'for', uno en el que se copian elementos al
nuevo vector y otro que desplaza elementos a la derecha. Se podran haber copiado
los elementos al nuevo vector ya desplazados una posicin a la derecha.
* EJERCICIO: Son 'add' y 'remove' mtodos duales? En otras palabras, sean 'a' y 'b'
dos objetos iguales de clase 'ArrayIndexList':
* Se cumple 'a.add(i,e).remove(i).equals(b)' para todo 'i' y 'e'?
* Se cumple 'a.add(i,a.remove(i)).equals(b)' para todo 'i' y 'e'?
* EJERCICIO: Implementar 'add' y 'remove' en trminos de un mtodo que mueve, a part
ir de una posicin dada tomada como primer parmetro, los elementos del vector a der
echa o izquierda segn el valor de un segundo parmetro booleano.
* EJERCICIO: Reescribir el cdigo de 'add' para que cuando se hace copia al nuevo
vector los elementos se copien desplazados una posicin a la derecha y finalmente
se inserte el nuevo elemento. Cuando no se hace copia los elementos se desplazan
dentro del propio vector como antes.
* EJERCICIO: El mtodo 'remove' no trata el dficit. Modificar el mtodo 'remove' para
que "decremente" N cuando n < N/4.
* Complejidad y costes amortizados
* Complejidad de los mtodos en el caso peor [Libro, p237]:
* Ha mejorado la complejidad de 'get' y 'set'.
set
remove
get
O(n)
add
isEmpty
O(1)
size
Complejidad
Mtodo
* El mtodo 'add' puede aumentar la capacidad del vector. Cmo afecta la complejidad?
El incremento de capacidad ocurre ocasionalmente, cuando hay N, 2*N, 3*N, etc,
inserciones.
* Definicin de coste amortizado: coste medio a lo largo de la ejecucin [Libro p241
-242].
* 6.2 Node Lists
* Material
* Libro: Seccin 6.2.
* Transparencias: list.pdf (indicamos en este guin cules utilizamos).
* Cdigo:
* Interfaces: Position.java y PositionList.java.
* Clases: EmptyListException.java, InvalidPositionException.java, BoundaryViolat
ionException, DNode.java, NodePositionList.java, ElementIterator.java.

* Motivacin de las listas de posiciones


* Abstraccin y eficiencia:
* En *Listas simplemente enlazadas y *Anlisis de la librera propuesta vimos un TAD
de listas con mtodos cuya implementacin manipula nodos. Algunos mtodos seran ms efic
ientes de implementar si se pudieran manipular directamente los nodos.
* La implementacin de los nodos debe quedar oculta.
* Las listas de posiciones ('position lists') son listas donde los mtodos de acce
so y modificacin utilizan un interfaz 'Position<E>' que abstrae la implementacin d
e nodos.
* El nombre no es afortunado, pues "position" sugiere una localizacin. Podramos ha
berlos llamado "nodos abstractos".
* Una posicin se concibe de forma relativa, en funcin de la posicin anterior o prev
ia ('before', 'previous') y la posicin posterior o siguiente ('after', 'next').
* La implementacin natural que veremos utilizar una lista doblemente enlazada ('do
ubly-linked list') de nodos.
* Los nodos sern objetos de una clase que implementar el interfaz 'Position<E>'.
* Diagrama de clases
* Interfaz PositionList<E> -- U --> Interfaz Position<E>
*
^
^
*
I |
| I
* Clase NodePositionList<E> ---- U ---> Clase DNode<E>
*
\
*
\-- U ---> Clase ElementIterator<E>
*
* U: Usa. I: Implementa.
* Omitimos las clases de excepciones 'EmptyListException', 'InvalidPositionExcep
tion' y 'BoundaryViolationException'.
* Interfaz Position<E>
* Una posicin es una abstraccin de un nodo. Slo nos interesa el elemento almacenado
: mtodo 'element'.
* Se define este interfaz por separado porque se utilizar con otros TADs ms adelan
te.
* Clase DNode<E>
* [Transparencia 4]
* Implementacin de nodos. Implementa 'Position<E>'.
* Referencias al nodo aterior ('prev') y siguiente ('next') que son de clase 'DN
ode<E>' y no de tipo 'Position<E>'. Por qu?
* Mtodos: constructor, "getters" y "setters", mtodo 'element' e 'InvalidPositionEx
ception'.
* El mtodo 'element' lanza una excepcin si el nodo no est encadenado. Por qu? Tiene se
ntido hacer esta comprobacin en esta clase en vez de en la implementacin de la cad
ena enlazada?
* EJERCICIO: Comparar con la *Clase Node<E> del primer tema.
* EJERCICIO: Podramos hacer ms comprobaciones 'InvalidPositionException'?
* EJERCICIO: Podramos usar 'DNode<E>' en la implementacin de una cadena simplemente
enlazada? En caso positivo, cmo se hara?
* Interfaz PositionList<E>
* Extiende Iterable<E> *6.3 Iterators.
* Vemos los mtodos en clase.
* Excepciones:
* 'EmptyListException': lanzada cuando el mtodo no puede aplicarse sobre la lista
es vaca.
* 'InvalidPositionException': lanzada cuando la posicin pasada al mtodo no es vlida
(legalidad). Ejemplo: objeto null.
* 'BoundaryViolationException': lanzada cuando la posicin pasada al mtodo no es es
la adecuada (control de rango). Ejemplo, 'list.prev(list.first())' lanzar la exc
epcin.
Ms sobre esto en *Clase NodePositionList<E>.
* Los mtodos 'first' y 'last' no declaran que lancen excepciones 'EmptyListExcept
ion', al contrario que en *Listas simplemente enlazadas. Esto no es correcto des

de el punto de vista de la usabilidad de la librera: el usuario de la librera no s


abe que esos mtodos lanzan excepciones y por tanto no los invocar dentro de un blo
que try-catch con el que podra capturar las excepciones.
* Insercin arbitraria: mtodos 'addBefore' y 'addAfter'.
* EJERCICIO: Tiene sentido un mtodo 'add(Position<E> p, E e)'?
* Clase NodePositionList<E>
* [Transparencias 4,5,7]
* ERRORES: 'insertAfter' debera ser 'addAfter'.
* Implementacin de listas de posiciones mediante una cadena doblemente enlazada.
* Nodos especiales 'header' y 'trailer' que no almacenan elementos.
* El constructor crea una lista vaca que consiste en un header y trailer encadena
dos.
* El mtodo protegido 'checkPosition' comprueba si una posicin (nodo) es vlida. Una
posicin es invlida cuando [Libro, p245]:
* Es 'null'.
* Es el nodo 'header' o 'trailer'
* No est encadenado.
(Ntese el "downcasting" en [Cdigo, lnea 37] y la clusula 'catch').
Otras posibles comprobaciones que no se hacen aqu:
* Es un nodo de otra lista. Se podra comprobar?
* Control de rango, p.ej, 'L.prev(L.first())'. Estas comprobaciones se hacen en
los mtodos pertinentes.
* Los mtodos 'first' y 'last' lanzan 'EmptyListException' (lo cual es correcto) a
unque el interfaz no lo declara. La excepcin est declarada en el fichero EmptyList
Exception.java del paquete net.datastructures.
* Ilustramos los mtodos 'addAfter', 'addBefore' y 'remove'.
* El mtodo 'positions' crea una nueva 'NodePositionList' con las posiciones de la
lista y el mtodo 'iterator' crea un 'ElementIterator<E>'. (De momento no entramo
s en los detalles de estos dos mtodos. Volveremos a ellos cuando veamos *6.3 Iter
ators y *Ejemplos de iteradores.
* Hay otros mtodos internos 'isFirst', 'isLast', 'swapElements' que no son usados
en otra parte de la librera.
* Los mtodos de serializacin a cadenas los veremos en *6.3 Iterators.
* Anlisis de las listas de posiciones
* Complejidad
* Complejidad en el caso peor de todos los mtodos, excepto de iteracin: O(1).
* EJERCICIO: Dado un elemento, si no se tiene su posicin entonces habra que buscar
la. Implementar el mtodo 'public Position<E> getPos(E e)' que devuelve la primera
posicin en la lista que contiene el elemento. Cul sera la complejidad de dicho mtodo
?
* Grado de abstraccin conseguido
* La implementacin de nodos queda oculta a los usuarios del interfaz 'PositionLis
t<E>'. No es necesario crear objetos de la *Clase DNode<E>, basta con usar los mt
odos del interfaz 'PositionList', guardando si necesario en variables de tipo 'P
osition' algunos objetos intermedios.
* PositionList<Integer> plist = new NodePositionList<Integer>();
* Position<Integer> p;
*
* plist.addFirst(50);
// (50)
* plist.addLast(42);
// (50,42)
* p = plist.first();
* plist.addAfter(p,41);
// (50,41,42)
* plist.set(p,40);
// (40,41,42)
* /* Aade a la lista un elemento e1 inmediatamente antes de otro
* * elemento e2 slo si este ltimo est en la lista.
* */
* public void addBeforeElement(PositionList<E> list, E e1, E e2) {
* if (!list.isEmpty()) {
*
Position<E> p = list.first();
*
int n = 1; // Estamos en en primer nodo

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

* for (int i=0, i < list.size(); i++)


* System.out.print(list.get(i) + " ");
* Ejemplo 2: Mostrar por pantalla los elementos almacenados en un objeto 'list'
que implementa el *Interfaz PositionList<E>:
* Position<E> p;
* for (int i=0, i < list.size(); i++) {
* if (i==0) p = list.first();
* else
p = list.next(p);
* System.out.print(p.element() + " ");
* }
o a lo "bestia" sabiendo que 'next' lanza una excepcin:
if (list.size() > 0) {
Position<E> p = list.first();
try {
while (true) {
System.out.print(p.element() + " ");
p = list.next(p);
}
} catch (BoundaryViolationException e) { }
}
* Ejemplo 3: Mostrar por pantalla los elementos almacenados en un objeto 'set de
tipo *Interfaz Set<E>:
Slo se dispone del mtodo observador 'member' con lo que no es posible recorrer el
conjunto en general usando los mtodos del interfaz.
S es posible recorrer conjuntos finitos 'BitVectSet<E>' usando los mtodos del inte
rfaz 'Set<E>', siempre que dispongamos de un valor del tipo enumerado 'E' sobre
el que poder usar reflexin. Supongamos que en la variable 'e' tenemos dicho valor
:
if (set.size() > 0) {
E [] v = e.getDeclaringClass().getEnumConstants();
for (int i=0; i < v.length; i++)
if (set.member(v[i])) System.out.print(v[i] + " ");
}
Finalmente, tambin es posible hacer un recorrido "desde dentro" de la implementac
in de la clase 'BitVectSet<E>':
public class BitVectSet<E extends Enum<E>> implements Set<E> {
protected boolean bv[];
protected E [] enumConstants; // Guardamos el vector de constantes
// aqu cuando se invoque 'add'.
...
public static void print() {
for (int i = 0; i < bv.length; i++)
if (bv[i]) System.out.println(enumConstants[i] + " ");
}
}
* Concepto de iterador
* En los ejemplos de la seccin anterior el cdigo del recorrido es especfico a cada
TAD. Se usan mtodos especficos de su interfaz y no siempre se puede usar el mismo
estilo de bucle.
* El iterador es un patrn de diseo ('design pattern') para recorrer linealmente lo
s elementos de TADs que almacenan elementos (ojo, no todos los TADs son coleccio
nes de elementos) tal que:
1. El recorrido no se hace a travs de los mtodos del interfaz del TAD sino a travs
de los mtodos de un interfaz nico 'Iterator'.
2. Permite usar el mismo estilo de bucle para todos los TADs.
* Conceptualmente, un objeto iterador mantiene una referencia a un objeto elemen
to del TAD, referencia que llamamos cursor.
Que dicha referencia sea un atributo del objeto iterador depende de cmo se defina
el iterador. Concretamente, en lo tocante a TADs se pueden definir objetos iter
ador para:

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())

System.out.print(it.next() + " ");


}
* Al crearse el objeto iterador:
* Si el TAD est vaco:
* hasNext() devuelve false.
* next()
lanza
NoSuchElementException.
* Si el TAD no est vaco:
* hasNext() devuelve true.
* next()
devuelve el primer elemento y avanza el cursor
*
al segundo elemento.
* Conceptualmente, el cursor es null cuando el TAD est vaco o cuando 'next' devuel
ve el ltimo elemento de la iteracin ('next' deja el cursor a null pues no hay elem
ento siguiente).
* Ahora podemos entender los nombres de los mtodos: el cursor referencia el sigui
ente elemento que todava no ha devuelto 'next', por tanto:
* 'hasNext' significa "hay un siguiente elemento en el cursor?"
* 'next' significa "dame ese siguiente elemento en el cursor y avanza el cursor"
.
* Cul es el primer elemento y cmo se avanza (orden de elementos) depende del TAD.
En el caso de las listas el orden lo determina la posicin que ocupa el elemento.
En el caso de conjuntos de enumerados el orden lo determina la posicin que ocupa
la constante enumerada en la declaracin 'enum'. Etc.
* Ejemplo: Tenemos un TAD con 2 elementos 'A' y 'B',
* Inicialmente el cursor referencia al primer elemento porque el TAD no es vaco.
* {A,B}
* ^
* |
* cursor
*
* hasNext() devuelve true.
* next()
devuelve A y avanza el cursor a B,
*
*
* {A,B}
*
^
*
|
* cursor
*
* hasNext() devuelve true.
* next()
devuelve B y avanza el cursor a null,
*
* {A,B}
*
*
cursor -> null
*
* hasNext() devuelve false.
* next()
lanza
NoSuchElementException.
* El mtodo 'remove' del iterador no se describe en detalle en [Libro, p254, 'Simp
le Iterators in Java']. No es obligatorio implementar la funcionalidad completa.
* Incompleto: slo lanza 'UnsupportedOperationException' (cuando es invocado). Est
e es el procedimiento habitual en la JCF para mtodos incompletos invocados.
* Completo: debe borrar del TAD el elemento al que referencia el cursor, lanzand
o 'IllegalStateException' si el cursor es null.
* Al iterar un TAD, ste slo puede modificarse (borrar elementos) con el 'remove' d
el iterador. No se deben usar mtodos de insercin o borrado del TAD durante la iter
acin pues el resultado de la misma puede ser impredecible.
* Cmo iterar sobre TADs
* Declaraciones y clases
El siguiente procedimineto permite definir iteradores para TADs usando los mtodos

de sus interfaces (alternativa 1 vista en *Concepto de iterador).


0. Hacer que el interfaz del TAD extienda 'Iterable<E>':
1. import java.util.Iterator;
2. public interface TAD<E> extends Iterable<E> {
3.
4. ... /* mtodos del TAD */
5.
6. public Iterator<E> iterator() ;
7. public Iterable<E> elements() ; /* no obligatorio pero til */
8. }
* El mtodo 'iterator' se hereda de 'Iterable<E>'.
* El mtodo 'elements' es nuevo, no se hereda de 'Iterable<E>'. No es obligatorio
declararlo, pero es til: 'snapshot' [Libro, p257], persistencia y mutabilidad (bo
rrado, [JP'05, p102]). Hablaremos de l ms adelante.
Que un TAD sea "iterable" (su interfaz extiende 'Iterable<E>') garantiza que se
tendr un iterador (objeto que implementa 'Iterator<E>') que se obtendr invocando '
iterator' y se usar para recorrer todas las implementaciones del TAD.
9. Implementar una clase iterador para el TAD:
10. import java.util.Iterator;
11. public class TADIterator<E> implements Iterator {
12.
TAD<E> tad;
13.
E cursor;
14.
public TADIterator(TAD<E> t) {
15.
tad = t;
16.
... /* cdigo aqu que inicializa el valor del cursor */
17.
}
18.
public boolean hasNext()
{ /* cdigo aqu */ }
19.
public E next()
{ /* cdigo aqu */ }
20.
public void remove()
{ /* cdigo aqu */ }
21. }
* El constructor toma como parmetro el objeto 't' (que implementa el interfaz 'TA
D<E>') sobre el que iterar. Lo almacena en un atributo interno de la clase.
* Se deben implementar 'next', 'hasNext' y 'remove' utilizando nicamente los mtodo
s del interfaz 'TAD<E>' sobre el atributo 'tad' (slo sabemos que implementa el in
terfaz 'TAD<E>'). Si esto no es posible entonces debemos asociar el iterador con
la implementacin del TAD (ver ms abajo).
22. Implementar el mtodo 'iterator' en todas las implementaciones del interfaz 'T
AD<E>':
23. import java.util.Iterator;
24. public class TADImpl1<E> implements TAD<E> {
25. ...
26. public Iterator<E> iterator() { return new TADIterator<E>(this); }
27. }
28.
29. public class TADImpl2<E> implements TAD<E> {
30. ...
31. public Iterator<E> iterator() { return new TADIterator<E>(this); }
32. }
33.
34. ...
35. Resumen:
36.
TAD<E> ----- E -----> Iterable<E> ------ U ----> Iterator<E>
37.
^ ^
^
38. I | | I
| I
39.
| \
|
40.
|
TADImpl2<E> ------------- U ---------------> TADIterator<E>
41. TADImpl1<E> --------------------- U --------------/
42.
43. E: Extiende.
44. I: Implementa.

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

* [Transparencia 6, iterators.pdf] [Libro, Seccin 6.3.4 'List Iterators in Java']


* En la JCF los interfaces de lista extienden 'Collection<E>' que a su vez extie
nde 'Iterable<E>'.
* No existe 'Position<E>' en JCF, los mtodos de listas usan ndices y/o elementos.
* Interfaces: 'List' (usa ndices) y 'ListIterator'. Hay adems clases abstractas: '
AbstractList', 'AbstractSequentialList', etc.
* Implementaciones (Java Platform SE 6): 'ArrayList', 'LinkedList', 'AttributeLi
st', 'CopyOnWriteArrayList', 'RoleList', 'RoleUnresolvedList', 'Stack', 'Vector'
.
* 'Fail-fast' para mltiple iteradores cuando uno modifica la coleccin [Libro, p259
].
* 4.2 Analysis of Algorithms
* Material
* Transparencias: analysis.pdf.
* Libro: Secciones 4.1 y 4.2.
La Seccin 4.1 repasa preliminares matemticos:
* Funcin constante, logaritmo, lineal, n-log-n, cuadrtica, cbica, polinomial y expo
nencial.
* Sumas aritmticas y geomtricas.
* Razones de crecimiento.
* Funciones techo ('ceiling') y suelo ('floor').
* Resumen de ideas
* La complejidad, eficiencia, o coste de un programa es la medida del tiempo de
ejecucin y del uso de memoria (espacio).
* La complejidad en tiempo y la complejidad en espacio suelen estar reidas: se ah
orra en tiempo a costa de consumir ms espacio y se ahorra espacio a costa de tard
ar ms tiempo. Por ejemplo *Conjuntos mediante listas.
* Cmo se mide la complejidad de un programa?
0. [Transparencias 3-4] Anlisis experimental. Hay que escribir el programa en un
lenguaje de programacin concreto. Requiere anlisis estadstico (con buen muestreo de
datos de entrada) y probabilstico (distribucin de dichos datos). Resultados depen
den del entorno de ejecucin (compilador, sistema operativo, arquitectura, entorno
dinmico, etc.)
1. [Transparencia 5 en adelante] Anlisis terico. Se fundamenta en las siguientes i
deas:
2.1 Se estudian algoritmos en pseudocdigo que son analizados independientemente d
e lenguajes y arquitecturas concretos.
Estamos interesados en la complejidad "intrnseca" del algoritmo, independiente de
l entorno de ejecucin.
El pseudocdigo es una notacin que abstrae (alto nivel) las particularidades de los
lenguajes de programacin (ojo, de un paradigma de programacin [Transparencia 8]).
La complejidad de las operaciones primitivas de un algoritmo descrito en pseudocd
igo es proporcional (funcin constante) a la complejidad real de su implementacin e
n un lenguaje de programacin concreto ejecutndose en entorno concreto. Por tanto,
la complejidad del algoritmo en pseudocdigo es proporcional (funcin constante) a l
a complejidad de su implementacin. Dicho de otro modo, los factores a tener en cu
enta en una implementacin real afectan la complejidad terica en un factor constant
e [Transparencia 14].
2.2 Se estudian programas ya implementados (p.ej., Java) asumiendo que la comple
jidad de las operaciones son proporcionales (funcin constante) a las de los algor
itmos en pseudocdigo.
2.3 La complejidad (tiempo o espacio) de un algoritmo es una funcin del tamao de l
a entrada ('input'). Esa funcin es o bien constante o bien crece en proporcin al t
amao de la entrada. (Se asume que no puede decrecer al crecer el tamao de la entra
da.)
El tamao de la entrada puede crecer indefinidamente. Daremos una medida de comple
jidad asinttica en *Notacin O() mediante una funcin del coste en tiempo (o espacio)
cuando el tamao de la entrada tiende a infinito.

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 ...

* public static <E> int height ...


* public static <E> String toStringPreorder ...
* public static <E> String toStringPostorder ...
* }
* EJERCICIO: Definir dicha clase.
* EJERCICIO: Se podra implementar dicha clase de forma que el rbol que se est recorr
iendo se almacene en un atributo y no tenga que pasarse como argumento a cada mto
do? En caso positivo, realizar los cambios necesarios en la clase para conseguir
lo.
* 7.3 Binary Trees
* Material
* [Trasparencias 7-15, 17-20, trees.pdf]
* Cdigo:
* Interfaces: BTPosition.java, BinaryTree.java.
* Clases: BTNode.java, LinkedBinaryTree.java, EmptyTreeException.java NonEmptyTr
eeException.java InvalidPositionException.java, BoundaryViolationException.java.
* Binary Trees: Terminologa y Definiciones
* [Libro, p296-297]
* Caso especial de rbol general en el que todo nodo tiene como mximo 2 hijos, el h
ijo izquierdo ('left child') y el hijo derecho ('right child'), que estn ordenado
s: el izquierdo precede al derecho.
* Definicin recursiva:
Un rbol binario es un rbol ordinario que es o bien vaco o bien un nodo raz con dos (
sub)rboles binarios izquierdo y derecho.
* El nodo hijo izquierdo/derecho es la raz del subrbol izquierdo/derecho.
* Definicin de rbol binario propio ('proper binary tree'), tambin llamado rbol estri
ctamente binario ('strictly binary tree'): todo nodo interno tiene 2 hijos. Equi
valentemente, todo nodo tiene o bien 0 o bien 2 hijos. Tambin llamado 2-Tree o rbo
l de grado 2.
*
o
*
/ \
* o o
* / \
* o o
* Definicin de rbol binario impropio ('improper binary tree'): rbol binario que no
es propio.
*
o
*
/ \
* o o
* / \ \
* o o o
* Definicin de rbol binario perfecto ('perfect binary tree'): rbol binario propio c
on el mximo nmero de nodos. El nmero de nodos de un rbol binario (propio o impropio)
es como mximo 2(h+1)-1. El nmero de nodos internos de un rbol binario (propio o im
propio) es como mximo 2h-1. *7.3.3 Properties of Binary Trees.
*
o
h
= 0
*
2^(h+1)-1 = 1
*
*
o
h
= 1
*
/ \
2^(h+1)-1 = 3
* o o
*
*
o
h
= 2
*
/ \
2^(h+1)-1 = 7
* o o
* / \ / \
* o oo o
Obsrvese que todas las hojas estn en el mismo nivel y todos los nodos internos tie
nen dos hijos.

* [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.

* Igual que en *Interfaz Tree<E>, no se definen mtodos modificadores [Libro, p298


]: "we will consider some possible update methods when we describe specific impl
ementations and applications of binary trees." Los mtodos modificadores se defini
rn en las clases que implementan el interfaz.
* Interfaz BTPosition<E>
* Cdigo: BTPosition.java.
* Recordamos que el *Interfaz Position<E> slo ofrece el mtodo 'element' que devuel
ve el elemento almacenado en el nodo.
* 'BTPosition<E>' extiende 'Position<E>' ofreciendo mtodos "setters" y "getters"
para el resto de informacin que se almacenar en los nodos como atributos: referenc
ias al nodo padre, al nodo hijo izquierdo y al nodo hijo derecho. Se aade un mtodo
"setter" 'setElement' para modificar el elemento almacenado en el nodo. El mtodo
'element' no hace falta declararlo porque se hereda de 'Position<E>'
* Obsrvese la diferencia entre el mtodo 'left', que devuelve el nodo hijo izquierd
o del objeto rbol sobre el que se invoca, y el mtodo 'getLeft' que devuelve el nod
o hijo izquierdo del objeto nodo sobre el que se invoca. El primero lanza una ex
cepcin si el nodo del rbol que toma como argumento no tiene hijo izquierdo mientra
s que el segundo no lanza ninguna excepcin, y por tanto podemos asumir que devolv
er 'null'. Dado un objeto 'tree' de una clase que implemente 'BinaryTree<E>' y un
objeto 'node' de una clase que implemente 'BTPosition<E>' podremos asumir que '
tree.left(p).equals(p.getLeft())' si 'p' es un nodo vlido que tiene hijo izquierd
o. Igualmente con 'right' y 'getRight'.
* Obsrvese que los mtodos observadores devolvern objetos de tipo (de clases que imp
lementen) 'BTPosition<E>'. No devuelven objetos de tipo 'Position<E>'. No tiene
sentido que devuelvan 'Position<E>', como tampoco que devolvieran 'Object'. La c
omprensin de este punto demuestra el conocimiento sobre el concepto de herencia q
ue tenga el alumno.
* Clase BTNode<E>
* Representacin de nodos: [Transparencia 17, trees.pdf] [Libro, p301].
* Cdigo: BTNode.java.
* Implementa 'BTPosition<E>'.
* Cuatro atributos: referencia al nodo padre, referencia al elemento, referencia
al hijo izquierdo y referencia al hijo derecho.
* Dos constructores, uno que crea un nodo vaco (en el que todos los atributos que
dan a null) y otro que construye un nodo dados valores para los atributos.
* Se implementa el mtodo 'element' del *Interfaz Position<E>.
* Clase LinkedBinaryTree<E>
* Cdigo: LinkedBinaryTree.java.
* Implementa el *Interfaz BinaryTree<E>.
* Ignoramos de momento los comentarios iniciales del cdigo que explican por qu en
esta clase se usa directamente el atributo 'size' en vez de invocar el mtodo 'siz
e' para obtener el nmero de nodos del rbol. (Se trata de un caso cuando menos cues
tionable de una clase padre cuya implementacin est determinada por clases hijas. V
olveremos sobre este punto en *10.1 Binary Search Trees.)
* Se definen slo dos atributos: el tamao 'size' y el nodo raz 'root'.
* El constructor crea un rbol vaco: 'root' a null y 'size' a 0.
* El mtodo protegido 'checkPosition' [Cdigo, lnea 283] es utilizado por varios mtodo
s para comprobar la validez de un nodo (de un objeto que implementa el *Interfaz
Position<E>). Un nodo es vlido si no es null y es un objeto que implementa el *I
nterfaz BTPosition<E>. Si el nodo es vlido se devuelve con casting a 'BTPosition'
. (Por qu no a 'BTPosition<E>'? Podra hacerse el casting a 'BTPosition<?>?)
Los mtodos que invocan 'checkPosition' utilizan una variable temporal ('vv', 'ww'
) de tipo 'BTPosition<E>' para almacenar el nodo porque el tipo esttico ha sido c
ambiado por el casting.
* Los mtodos 'isRoot', 'isInternal' e 'isExternal' implementan respectivamente la
s definiciones de riz, nodo interno y nodo externo que hemos visto en *General Tr
ees: Terminologa y Definiciones.
* Los mtodos 'hasLeft', 'hasRight', 'left', 'right' y 'parent' descansan en los "
getters" del nodo, como anticipamos en *Interfaz BTPosition<E>. El mtodo 'root' c
onsulta el valor del atributo 'root' y el mtodo 'isRoot' descansa en el mtodo 'roo

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

devuelve el valor (elemento) de menor clave (mayor prioridad). La complejidad de


ste mtodo debe ser la mejor posible. En Java, utilizaremos tipos (interfaces, cla
ses, etc) para claves y valores, que sern parmetros del interfaz de colas con prio
ridad.
* Las claves y valores van por separado. La asignacin de claves a valores depende
del problema. En ocasiones puede usarse como clave un atributo del valor (p.ej.
, el precio de un libro), pero debe tenerse un interfaz o clase aparte para pode
r ser usado el tipo clave como parmetro genrico:
* public class Precio { ... }
* public class Libro {
*
Precio precio;
*
String editorial;
*
...
* }
* public class Main {
* PriorityQueue<Precio,Libro> cola = new ... ;
* ...
* }
* [Libro, p334] Relaciones entre claves (prioridades) y valores (elementos), usa
mos la letra 'k' para claves y la letra 'v' para valores:
* Dos entradas '(k,v1)' y '(k,v2)' con valores distintos pueden tener la misma c
lave: elementos distintos pueden tener la misma prioridad.
* Dos entradas '(k1,v)' y '(k2,v)' con los mismos valores pueden tener claves di
stintas: el mismo elemento puede tener distintas prioridades.
* Puede modificarse la clave o el valor de una entrada. La prioridad de un eleme
nto puede cambiar.
* 8.1 The Priority Queue Abstract Data Type
* 8.1.1 Keys, Priorities, and Total Order Relations
* En esta seccin estudiamos el concepto matemtico de orden total, tambin llamado or
den lineal.
* Desde la perspectiva de teora de conjuntos, una entrada es un par perteneciente
al producto cartesiano de un conjunto 'K' de claves y un conjunto 'V' de valore
s: '(k,v)' est en 'K x V'.
* Hay una relacin de orden total computable '<=' sobre el conjunto de claves K.
La siguiente definicin elabora la que hay en [Transparencia 3] y en [Libro, p335]
:
1. Hay una relacin de igualdad computable (existe un programa que la computa) en
K que permite determinar si una clave es igual o no a otra.
2. Hay una relacin total computable (hay un programa que la computa) que satisfac
e las siguientes leyes:
* Totalidad: o bien 'k1 <= k2' o bien 'k2 <= k1'.
* Antisimtrica: Si 'k1 <= k2' y 'k2 <= k1' entonces 'k1 = k2'.
* Transitiva: Si 'k1 <= k2' y 'k2 <= k3' entonces 'k1 <= k3'.
Totalidad y antisimtrica implican reflexiva: 'k <= k'.
* Una relacin entre dos elementos se computa mediante un programa que toma los do
s elementos y devuelve un booleano que indica si el par est o no en la relacin.
* Ejemplos de rdenes totales: naturales, cadenas de caracteres. Ejemplo de orden
parcial: relacin de subconjunto.
* Todo orden total lleva asociado un orden total estricto '<':
* 'k1 < k2' si y slo si 'k1 <= k2' y 'k1 != k2'.
Se puede definir ste orden porque tenemos igualdad.
* En la prctica se desea tener conjuntos K en el que hay una clave mnima y o bien
una clave mxima o bien un supremo:
* Clave mnima 'kmin': 'kmin <= k', para toda clave 'k'.
* Clave mxima 'kmax': 'k <= kmax', para toda clave 'k'.
* Supremo: se toma la unin de K con un conjunto formado por un nico elemento 'sup'
y se extiende la relacin de orden tal que 'k <= sup' para toda 'k'.
* En *Interfaces Comparable<T> y Comparator<T> vemos cmo se define un orden total
en Java.
* 8.2.1 Entries and Comparators

* 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.

You might also like