Implementación de iteradores en C++

Anuncio
Clase de Iteradores en C++
Algoritmos y estructuras de datos II
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
Hasta ahora vimos:
I
Clases
I
Manejo de memoria dinámica
I
Templates
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
template < typename T >
class ArregloD {
T*
arreglo ;
int espacio ;
int ultimo ;
public :
ArregloD ();
ArregloD ( int tamanio );
ArregloD ( const ArregloD <T >& otroArreglo );
~ ArregloD ();
void insertarAtras ( const T & elem );
int tamanio () const ;
const T & iesimo ( int i ) const ;
T & iesimo ( int i );
};
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
Iteradores
I
¿Qué es un iterador?
I
I
I
Un objeto que permite atravesar un contenedor.
En general mantienen una interfaz común y ocultan los
detalles de la estructura que iteran.
¿Cómo los usamos en C++?
I
I
En C++ los contenedores iterables contienen una clase interna
llamada iterator y métodos para obtener una instancia que
itere a partir de algún punto.
El estilo de C++ es levemente distinto al estilo que usamos en
la materia en los módulos de diseño, en el TP podrán utilizar
el que les sea más cómodo.
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
Declarando un iterador à la Algo 2
template < typename T >
class ArregloD {
public :
...
class Iterador {
ArregloD <T >* arreglo ;
int indice ;
Iterador ( ArregloD <T >* arreglo , int indice );
friend Iterador ArregloD <T >:: crearIt (); // Lo que ?
public :
bool hayMas () const ;
T&
actual ();
void avanzar ();
};
Iterador crearIt ();
};
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
Definiendo un iterador à la Algo 2
template < typename T >
typename ArregloD <T >:: Iterador
ArregloD <T >:: crearIt () {
Iterador it ( this , 0);
return it ;
}
template < typename T >
ArregloD <T >:: Iterador :: Iterador (
ArregloD * a , int i ) :
arreglo ( a ) , indice ( i ) {}
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
Definiendo un iterador à la Algo 2
template < typename T >
bool ArregloD <T >:: Iterador :: hayMas () const {
return indice < arreglo - > tamanio ();
}
template < typename T >
T & ArregloD <T >:: Iterador :: actual () {
return arreglo - > iesimo ( indice );
}
template < typename T >
void ArregloD <T >:: Iterador :: avanzar () {
indice ++;
}
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
Definiendo un iterador à la Algo 2
¿Qué sucede con el siguiente código?
const ArregloD < int >& a = de Al g un aF un c io n ();
ArregloD < int >:: Iterador it = a . crearIt ();
if ( it . hayMas ()) {
int & e = it . actual ();
cout << e ;
e = 2;
}
¿Y si sacamos el const?
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
Declarando un iterador à la Algo 2
template < typename T >
class ArregloD {
public :
...
class It erador_c onst {
const ArregloD <T >* arreglo ;
int indice ;
Iter ador_con st ( const ArregloD <T >* arreglo , int indice );
friend Itera dor_cons t ArregloD <T >:: crearIt () const ;
public :
bool hayMas () const ;
const T & actual ();
void avanzar ();
};
Iter ador_con st crearIt () const ;
};
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
Definiendo un iterador à la Algo 2
template < typename T >
typename ArregloD <T >:: Iterad or_const
ArregloD <T >:: crearIt () const {
Iter ador_con st it ( this , 0);
return it ;
}
template < typename T >
ArregloD <T >:: Itera dor_con st :: I terador_ const (
const ArregloD * a , int i ) :
arreglo ( a ) , indice ( i ) {}
template < typename T >
const T & ArregloD <T >:: Itera dor_con st :: actual () {
return arreglo - > iesimo ( indice );
}
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
Ventajas:
I
Permite manipular eficientemente el contenedor manteniendo
oculta su representación interna.
I
Podemos usar iteradores como “punteros seguros” a la
estructura interna sin exponerla.
I
Permite escribir algoritmos genéricos (asumiendo una interfaz
común).
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
template < typename T >
class Lista {
struct Nodo {
T elem ;
Nodo * anterior , * siguiente ;
Nodo ( const T & e , Nodo * ant , Nodo * sig ) :
elem ( e ) , anterior ( ant ) , siguiente ( sig ) {}
};
Nodo * cabeza ;
public :
class Iterador {
Lista <T >* lista ;
Nodo * nodo ;
Iterador ( Lista * lista , Nodo * nodo );
friend class Lista <T >;
public :
Iterador insertar ( const T & e );
void remover ();
};
Lista ();
Iterador agregar ( const T & t );
};
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
template < typename T >
Lista <T >:: Lista () : cabeza ( NULL ) {}
template < typename T >
typename Lista <T >:: Iterador
Lista <T >:: agregar ( const T & e )
{
cabeza = new Nodo (e , NULL , cabeza );
if ( cabeza - > siguiente != NULL )
cabeza - > siguiente - > anterior = cabeza ;
typename Lista <T >:: Iterador it ( this , cabeza );
return it ;
}
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
template < typename T >
Lista <T >:: Iterador :: Iterador ( Lista <T >* l , Nodo * n ) :
lista ( l ) , nodo ( n ) {}
template < typename T >
typename Lista <T >:: Iterador
Lista <T >:: Iterador :: insertar ( const T & e )
{
Nodo * nuevo = new Nodo (e , nodo , nodo - > siguiente );
if ( nuevo - > siguiente != NULL )
nuevo - > siguiente - > anterior = nuevo ;
nodo - > siguiente = nuevo ;
Iterador it ( lista , nuevo );
return it ;
}
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
template < typename T >
void Lista <T >:: Iterador :: remover ()
{
if ( nodo == lista - > cabeza ) {
lista - > cabeza = nodo - > siguiente ;
nodo - > siguiente - > anterior = NULL ;
} else {
nodo - > anterior - > siguiente = nodo - > siguiente ;
if ( nodo - > siguiente != NULL )
nodo - > siguiente - > anterior = nodo - > anterior ;
}
delete nodo ;
}
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
¡A la consola!
Ejercicio 1. Implementar las siguientes funciones en lista.h
template < typename T >
class Lista {
class Iterador {
bool haySiguiente ();
T & actual ();
void avanzar ();
}
Iterador crearIt ();
}
Ejercicio 2. Implementar las siguientes funciones fuera de la clase
lista (usando los iteradores ;-) )
int cant ( Lista <T >& l ); // cantidad de elementos de l
string to_s ( Lista <T >& l ); // string con el contenido de l
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
¡A la consola!
Contexto. Se dispone de un registro de personas donde las
mismas se anotan informando su nombre y edad. Se desea poder
obtener listados de aquellas personas que hayan alcanzando al
menos cierta edad.
Ejercicio 3. Se cuenta con la implementación del registro en
C++, pero no del iterador. Completar la implementación
aprovechando el iterador de listas de los módulos básicos.
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
Recomendaciones al pasar del diseño a la implementación
I
Por cada módulo hacer una clase y un test.
I
Hacer una clase interna por cada iterador en el módulo (y una
análoga const si tiene sentido).
I
Recordar que las clases templatizadas no forman unidades de
compilación (ojo con los cpp que no deben compilarse).
I
Tener siempre presente el scope de las variables y los objetos.
I
Identificar qué cosas deben alocarse en memoria dinámica y
qué cosas no.
I
Hacer delete de todo lo que se hace new, pero de nada más.
I
LO MAS IMPORTANTE DE TODO ES PROGRAMAR DE
FORMA INCREMENTAL. ESCRIBIR UNA FUNCIÓN, SU
TEST, COMPILAR Y PROBAR ANTES DE SEGUIR.
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
¿Cómo se hace el diseño de esto?
Por lo general . . .
I
Se va a definir un género de módulo por cada iterador
I
que se explican con secu(α), itUni(α), itMod(α), itBi(α) o
similar.
I
La operación que devuelve el iterador va a describir
funcionalmente la secuencia a recorrer,
I
a pesar de que la implementación no genere dicha lista.
I
Habrán operaciones para soportar la interfáz de un iterador,
I
cuyas axiomatizaciones serán casi triviales,
I
a pesar de que la implementación haga cosas muy
complicadas.
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
Iteradores à la C++
C++, Java, Python y muchos otros lenguajes hace un uso intensivo
de iteradores, cada uno tiene su propia manera de hacerlos.
En C++:
I
Los iteradores deben proveer los operadores *, ++, ->, == y
otros dependiendo del tipo del iterador.
I
Los objetos iterables usualmente tiene una clase interna
iterator (y/o const iterator) de forma similar a como lo
hicimos hasta ahora.
I
Los objetos iterables usualmente aceptan los métodos
begin() y end() (y potencialmente rbegin() y rend()).
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
template < typename T >
class Lista {
Nodo * cabeza ;
Nodo * fin ;
...
public :
class iterator {
Lista <T >* lista ;
Nodo * nodo ;
bool valido ;
...
public :
T & operator *();
bool operator ==( const Lista <T >:: iterator & otro ) const ;
bool operator !=( const Lista <T >:: iterator & otro ) const ;
iterator & operator ++();
iterator operator ++( int );
iterator & operator - -();
iterator operator - -( int );
};
iterator begin ();
iterator end ();
};
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
template < typename T >
T & Lista <T >:: iterator :: operator *() {
return nodo - > elem ;
}
template < typename T >
typename Lista <T >:: iterator & Lista <T >:: iterator :: operator ++() {
valido = nodo - > siguiente != NULL ;
if ( valido )
nodo = nodo - > siguiente ;
return * this ;
}
template < typename T >
typename Lista <T >:: iterator Lista <T >:: iterator :: operator - -( int ) {
iterator it (* this );
valido = nodo - > anterior != NULL ;
if ( valido )
nodo = nodo - > anterior ;
return it ;
}
template < typename T >
bool Lista <T >:: iterator :: operator ==(
const Lista <T >:: iterator & otro ) const {
return valido == otro . valido && nodo == otro . nodo ;
}
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
Algoritmos genéricos sobre iteradores en C++
El header algorithm tiene definidas un gran número de funciones
con clases templatizadas asumiendo que cumplen con la interfaz de
los iteradores. Por lo que cualquier clase que que siga
correctamente el patrón automáticamente tiene todos esos
algoritmos a su disposición sin necesidad de implementarlos.
Ejemplos:
I
find
I
count
I
replace
I
reverse
I
sort
I
random shuffle
I
min
I
max
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
Algoritmo de búsqueda de algorithm.h
template < class InputIterator , class T >
InputIterator find (
InputIterator first ,
InputIterator last ,
const T & value )
{
for (; first != last && * first != value ; ++ first );
return first ;
}
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
Tipos de iteradores
Los iteradores en C++ se separan en distintas categorı́as, lo que
permite implementar algoritmos genéricos de distinta forma para
cada tipo de iterador:
1. Input
2. Output
3. Forward
4. Bidirectional
5. Random access
Para definir a qué categorı́a pertenece un iterador se utilizan
miembros de la clase iterator traits. Esto puede hacerse de
distintas formas, pero usualmente incluye herencia o
especialización de templates por lo que queda fuera de este curso.
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
Ejercicio
Implemente una clase Rosetree (un árbol con una cantidad
arbitraria de hijos) con un iterador preorder à la C++.
Permita agregar y eliminar elementos a través del iterador
retornando un iterador nuevo cuando corresponda.
Puede hacer uso de las listas enlazadas y los algoritmos sobre
iteradores de la librerı́a standard:
# include < list >
# include < algorithm >
En la página http://www.cplusplus.com/reference/ pueden
encontrar la documentación de estos módulos.
Algoritmos y estructuras de datos II
Clase de Iteradores en C++
Descargar