viernes, julio 27, 2007

A continuación veremos unos pequeños ( y muy sencillos) ejemplos de uso de algunos de los algoritmos de la librería STL. No soy ni mucho menos un experto pero creo que pueden servir de ayuda si alguien quiere iniciarse en la programación genérica.

En primer lugar definamos un problema; chorras claro está, aunque servirá para nuestros didácticos propósitos. Imaginemos que estamos desarrollando una aplicación que situa puntos en un plano, es decir, nos indica la posición que los objetos tendrían en un mapa. Además supongamos que se nos presenta el problema de determinar si un determinado punto está contenido en una colección de coordenadas determinada. Vamos a resolver este sencillo problema utilizando la librería STL. Comenzemos:

En primer lugar seleccionamos la utilidad std::pair como reprentación de las coordenadas en el plano. Definimos un typedef para no tener que teclear todo el tipo anterior. Algo como lo que sigue:

typedef std::pair COORDENADA_PLANO;

Definamos ahora una colección de puntos en el plano:

//! 1. Vector de puntos del plano
std::vector puntos;

puntos.push_back(std::make_pair(1,1));
puntos.push_back(std::make_pair(-1,1));
puntos.push_back(std::make_pair(3,1));
puntos.push_back(std::make_pair(1,3));
puntos.push_back(std::make_pair(2,1));
puntos.push_back(std::make_pair(1,-2));
puntos.push_back(std::make_pair(3,8));
puntos.push_back(std::make_pair(1,1));
puntos.push_back(std::make_pair(1,1));
puntos.push_back(std::make_pair(3,8));

También podríamos rellenar el vector anterior del siguiente modo (con número pseudo-aleatorios)

std::fill(puntos.begin(),puntos.end(),std::make_pair(rand(),rand()));

La función anterior aplica, desde el comienzo [ begin() ] hasta el final del vector [ end() ], a cada uno de los elementos la función std::make_pair. El functor que se pasa como tercer argumento a este algortimo no espera argumentos.

Pensemos ahora que queremos comparar el punto (3,8) con el la colección de puntos definida en el paso anterior; y que además queremos que dicho puntos nos queden almacenados en otra estructura de datos, por ejemplo,en otro vector. Una posible solución,entre la multitud de ellas que podríamos aplicar, es la siguiente:

//2. Vector de puntos que coindicen con A
std::vector match;
std::remove_copy_if(puntos.begin(),
puntos.end(),std::back_inserter(match),
std::bind2nd(AreDistinct(),A));

En un principio puede parecer complicado pero ya vereis como es muy sencillo:

El algortimo std::remove_copy_if(...) copia aquellos elementos comprendidos en el intervalo [begin,end) al rango comenzado por match, salvo aquellos elementos para los que AreDistinct retorna cierto. Necesitamos un par de artifactos más:

  1. Dado que en un principio no sabemos cuantos elementos coincidiran con A declaramos un iterador de tipo std::back_inserter sobre nuestro vector destino match. De este modo cada coincidencia que el algoritmo encuentre será colocada tras la última.
  2. El algoritmo itera por toda la colección de puntos, y le aplica el functor AreDistinct. Dicho functor espera dos argumentos: el que le pasa el algoritmo en cada una de las iteraciones y el que nosotros queremos comparar con el resto de la colección. Necesitamos hacer un "binding" del segundo argumento: para ello actuamos del siguiente modo: std::bind2nd(AreDistinct(),A) con lo que estamos "forzando" que cada uno de los elementos del vector puntos se compare con A.
Finalmente, si imprimiésemos el resultado de una ejecución con una instrucción parecida a esta:
std::for_each(match.begin(),match.end(),Print_Coordenada(std::cout));

Obtendríamos que los puntos (3,8) y (3,8) coindicen con el punto A=(3,8). Como bien se observa en el código esos dos puntos son los únicos idénticos al punto A.

En el directorio que teneis a la derecha podeis descargaros los fuentes completos del ejemplo (ya vereis que es muy sencillo). Está en la carpeta CodeAndExamples, en el subdirectorio STL; es el archivo algorithms-1.tgz.

Hasta mañana!

No hay comentarios: