Está en la página 1de 9

Estructura de Datos I 2021

Tema I: Listas y Multilistas

Título: Iteradores.
Bibliografía:
1. Weiss, M. A., “Estructura de Datos en Java. Compatible con Java 2”:
Cap. 16
1. Desarrollo
Hasta el momento hemos visto las diferentes implementaciones que se le
pueden hacer al TDA Lista.
Ahora, una vez que tengamos almacenado en una lista una serie de elementos
necesitaremos hacer operaciones sobre ellos, por ejemplo, buscar un elemento
que cumpla con una condición determinada, calcular algún dato con la
información de los nodos, etc. En el caso de las listas secuenciales se puede
acceder directamente a sus elementos con el operador [ ], mientras en las listas
enlazadas, para acceder a un elemento debemos comenzar por el inicio hasta
llegar a él, si hiciéramos esta operación para cada elemento de la lista el
recorrido sería muy ineficiente.
Otra forma de realizar esta operación sería implementar un método dentro de la
misma clase LinkedList que utilizando los atributos propios de la estructura
resuelva el problema o permitiendo que esos atributos sean accedidos por
otras entidades dando a conocer la estructura interna de la clase. Sin embargo
esto iría en contra de los principios fundamentales de la POO, como la
Abstracción y el Encapsulamiento.
Estas operaciones las podemos realizar eficientemente mediante el uso de
iteradores.
Un iterador es un mecanismo que se encarga de recorrer una lista
enlazada con el fin de realizar acciones sobre sus elementos.
Los iteradores tienen un cursor, del mismo tipo que los nodos que componen la
lista, para indicar en cada momento cual es el elemento actual de la lista.
Como una solución al problema de recorrer una estructura de datos sin que sea
necesario conocer la estructura interna de la misma surge el patrón de diseño:
Iterador

¿Que es un patrón de Diseño?


Estructura de Datos I 2021

"Un patrón describe un problema que ocurre infinidad de veces en nuestro


entorno, así como la solución al mismo, de tal modo que podemos utilizar esta
solución un millón de veces más adelante sin tener que volver a pensarla otra
vez.

1979 arquitecto Christopher Alexander

 En 1987 se dieron cuenta del paralelo que existía entre la buena


arquitectura propuesta por Alexander y la buena arquitectura Orientada
a Objetos.

 En 1990 los patrones de diseño tuvieron un gran éxito en el mundo de la


informática a partir de la publicación del libro Design Patterns escrito por
el grupo Gang of Four (GoF)

Los patrones de diseño pretenden:

 Proporcionar catálogos de elementos reusables en el diseño de sistemas


software.
 Evitar la reiteración en la búsqueda de soluciones a problemas ya
conocidos y solucionados anteriormente.
 Estandarizar el modo en que se realiza el diseño.
 Facilitar el aprendizaje de las nuevas generaciones de diseñadores
condensando conocimiento ya existente.

El patrón Iterador es un mecanismo de acceso a los elementos que constituyen


una estructura de datos para la utilización de estos sin exponer su estructura
interna.
El patrón surge del deseo de acceder a los elementos de un contenedor de
objetos (por ejemplo, una lista) sin exponer su representación interna. Además,
es posible que se necesite más de una forma de recorrer la estructura siendo
para ello necesario crear modificaciones en la clase.
La solución que propone el patrón es añadir métodos que permitan recorrer la
estructura sin referenciar explícitamente su representación. La responsabilidad
del recorrido se traslada a un objeto iterador.
Estructura de Datos I 2021

El problema de introducir este objeto iterador reside en que los clientes


necesitan conocer la estructura para crear el iterador apropiado.
Esto se soluciona generalizando los distintos iteradores en una abstracción y
dotando a las estructuras de datos de un método de fabricación que cree un
iterador concreto.

<<interface>>
<<interface>>
Iterator<E>
Iterable<E>
+ hasNext(): boolean
+ iterator(): Iterator<E>
+next(): E
+ remove()

<<class>>
LinkedList<E> <<class>>
LinkedIterator<E>
+ size(): entero -cursor: Node<E>
+ get(index: entero): E
+ add(e: E)
+ add(e: E, index: entero)
+ remov(index: entero): E
+ isEmpty( ) : lógico
+ clear()
+ iterator():Iterator<E>

Para lograr esto se utiliza la interface Iterable, la cual está incluida en el api de
Java. Esta interfaz obliga a sobreescribir un método que es iterator(), el cual
debe devolver un objeto de tipo Iterator.
Lo primero que vamos a recordar es que una interface es un tipo abstracto: no
puede ser instanciado porque carece de constructor. Sin embargo, puede
definirse un objeto del tipo definido por la interface si se instancia en una clase
que implementa la misma. Esto puede parecer complicado pero con un ejemplo
lo veremos claramente:
List <Persona> miListaDePersonas = new List<Persona> (); es erróneo ¿Por
qué? Porque List es una interface y carece de constructor. En cambio sí sería
una escritura correcta definir como de tipo List una colección que creamos
instanciándola con una clase que tiene implementada la interface List como es
ArrayList: List <Persona> miListaDePersonas = new ArrayList<Persona> ();
De la misma manera que no podemos usar un constructor de List, tampoco
podremos usar un constructor para Iterator porque igualmente se trata de una
interface sin constructor.
Estructura de Datos I 2021

Veamos lo antes expuesto a través del código.


La clase que implementa la interfaz (Iterable) solo debe tener el método que
crea el iterador, teniendo en cuenta que para crearlo debe pasarle una
referencia de la lista.
public class LinkedList<E> implements List<E>,Iterable <E>
{
...
@Override
public Iterator<E> iterator()
{
return new LinkedIterator<E>(this);
}

Ahora bien como vemos debemos devolver un objeto de la clase Iterator. El tipo
Iterator es un tipo definido por una interface (al igual que List) y que no puede ser
instanciado directamente, ya que carece de constructor. Dicho de otra manera, la
clase Iterator es una clase abstracta.

Para poder devolver un objeto de tipo Iterator (que es algo a lo que al fin y al cabo nos
obliga la interface Iterable) necesitamos instanciar un objeto Iterator y esto no
podemos hacerlo directamente. Para resolver este problema, recurrimos a definir la
clase LinkedIterator, que implementará la interface Iterator y que será el iterador de la
lista.

public class LinkedIterator<E> implements Iterator<E> {

private Node<E> cursor;

public Iterator(LinkedList<E> list) {


this.cursor = list.getfirst();
}

public boolean hasNext() {


return cursor != null;
}

public E next() {
if (hasNext()) {
Node<E> aux=cursor;
cursor = cursor.getNext();
return aux.getInfo();
}
return null;
}
}
Estructura de Datos I 2021

La interface Iterator (del paquete java.util) a su vez nos obliga a implementar al


menos 3 métodos que son: public boolean hasNext(), public E next() y
public void remove().

El primero debe devolver un valor boolean indicando si el iterador tiene un


siguiente elemento. El método next(), debe devolver el siguiente elemento del
iterador, y remove() debe remover o eliminar el anterior objeto devuelto.

Veamos los siguientes ejemplos:


Dada una lista de números enteros: Contar todos los números 2 que existen en
la lista.
Iterator<Integer> it = l.iterator();
int cont = 0;
while (it.hasNext()) {
if (it.next() == 2) {
cont++;
}
}
System.out.println("La cantidad de dos es:"+ cont);

otra manera de recorrer la lista es a través del uso del bucle for-each, lo cual es
poible debido a que la clase LinkedList implementa la interfaz Iterable.
for (Integer e : l) {
if( e==2)
cont++;
}

2. Dada una lista de estudiantes, obtener:


a) los que cumplen años en el mes de mayo
b) la cantidad de militantes de la UJC
c) la cantidad de becados
d) el nombre de una estudiante becada y militante de la UJC
De cada estudiante se conoce: CI, nombre, apellido, sexo, si es militante
de la UJC y si es becado.

public class Estudiante {

private String ci;


private String nombre;
private String apellido;
private String sexo;
private boolean militante;
private boolean becado;
Estructura de Datos I 2021

/**
* @return the ci
*/
public String getCi() {
return ci;
}

/**
* @param ci the ci to set
*/
public void setCi(String ci) {
this.ci = ci;
}

/**
* @return the nombre
*/
public String getNombre() {
return nombre;
}

/**
* @param nombre the nombre to set
*/
public void setNombre(String nombre) {
this.nombre = nombre;
}

/**
* @return the apellido
*/
public String getApellido() {
return apellido;
}

/**
* @param apellido the apellido to set
*/
public void setApellido(String apellido) {
this.apellido = apellido;
}

/**
* @return the sexo
*/
Estructura de Datos I 2021

public String getSexo() {


return sexo;
}

/**
* @param sexo the sexo to set
*/
public void setSexo(String sexo) {
this.sexo = sexo;
}

/**
* @return the militante
*/
public boolean isMilitante() {
return militante;
}

/**
* @param militante the militante to set
*/
public void setMilitante(boolean militante) {
this.militante = militante;
}

/**
* @return the becado
*/
public boolean isBecado() {
return becado;
}

/**
* @param becado the becado to set
*/
public void setBecado(boolean becado) {
this.becado = becado;
}
}

public class Grupo {

LinkedList<Estudiante> listadodeestudiantes;

public Grupo() {
listadodeestudiantes = new LinkedList<Estudiante>();
}
Estructura de Datos I 2021

public String mes(String ci) {


returnci.substring(2, 4);
}

public LinkedList<Estudiante> cumplemayo() {


LinkedList<Estudiante> l = new LinkedList<>();
Iterator<Estudiante>it = listadodeestudiantes.iterator();
while (it.hasNext()) {
Estudiante estudiante = it.next();
if ("05".equals(mes(estudiante.getCi()))) {
l.add(estudiante);
}

}
return l;

public LinkedList<Estudiante> cumplemayoconforextendido() {


LinkedList<Estudiante> l = new LinkedList<>();
for (Estudiante estudiante : listadodeestudiantes) {
if ("05".equals(mes(estudiante.getCi()))) {
l.add(estudiante);
}
}
return l;
}

publicintcantidaddemilitantes() {
intcont = 0;
for (Estudiante estudiante : listadodeestudiantes) {
if (estudiante.isEsmilitante()) {
cont++;
}
}
returncont;
}

public int cantidaddebecados() {


int cont = 0;
for (Estudiante estudiante : listadodeestudiantes) {
if (estudiante.isEsbecado()) {
cont++;
}
}
return cont;
}

public String militanteybecada() {


int cont = 0;
for (Estudiante estudiante : listadodeestudiantes) {
if (estudiante.isEsmilitante() && estudiante.isEsbecado() &&
estudiante.getSexo() == "Femenino") {
return estudiante.getNombre();
}
}
returnnull;
}
Estructura de Datos I 2021

Conclusiones
 El uso de iteradores nos permiten recorrer una lista para realizar
acciones sobre sus nodos.
 Existen un patrón de diseño que resuelve este problema, patrón
Iterador.
Los iteradores tienen 3 funciones principales: saber si terminó, avanzar
al siguiente nodo y eliminar el elemento actual.
Estudio independiente
Dada la lista de profesores del departamento docente de un CES, defina e
implemente las clases y los métodos que permitan:
a) Dada una categoría científica y una edad obtener el nombre del
primer profesor (si existe) que tenga esa categoría y que tenga
como mínimo esa edad.
b) Obtener todos los profesores que tengan la mayor edad en el
departamento.
De cada profesor se conoce nombre, edad, categoría docente
(instructor, asistente, auxiliar, titular o ninguna), categoría científica
(master, doctor o ninguna) y cargo (jefe de disciplina, jefe de asignatura,
jefe de año, director, ninguno).
c) Conocer la cantidad de instructores, asistentes, masters y
doctores del departamento.
d) Conocer si existe algún profesor que sea instructor y doctor.
e) Determinar si hay más doctores que masters en el departamento.
f) Determinar si todos los jefes de asignatura son al menos
profesores asistentes.

También podría gustarte