Programación 2 Diseño recursivo de algoritmos que trabajan con ficheros Problemas 1 En los problemas que siguen se va a trabajar con ficheros binarios de datos de tipo T : <fichero_binario_T> ::= { <dato> } <dato> ::= T Asumiremos definidas las siguientes operaciones binarias de relación entre un par de datos, a y b, de tipo T : a == b a != b a < b a <= b a > b a >= b 2 Problema 1. Diseñar sin bucles: /* * Pre: [nombre1] y [nombre2] son los nombres de dos ficheros * binarios que almacenan secuencias de datos de tipo T * Post: Devuelve cierto si y sólo si ambos ficheros almacenan * el mismo número de datos */ template <typename T> bool igualLongitud (const char nombre1[], const char nombre2[]); 3 /* * Pre: [nombre1] y [nombre2] son los nombres de dos ficheros * binarios que almacenan secuencias de datos de tipo T * Post: Devuelve cierto si y sólo si ambos ficheros almacenan * el mismo número de datos */ template <typename T> bool igualLongitud (const char nombre1[], const char nombre2[]); /* * Pre: [f1] y [f2] están asociados a dos ficheros binarios que * almacenan secuencias de datos de tipo T * Post: Devuelve cierto si y sólo si los ficheros asociados a f1 * y f2 almacenan, en el momento de ser invocada esta * función, un mismo número de datos no leídos */ template <typename T> bool igualLongitud (ifstream& f1, ifstream& f2); 4 /* * Pre: [nombre1] y [nombre2] son los nombres de dos ficheros * binarios que almacenan secuencias de datos de tipo T * Post: Devuelve cierto si y sólo si ambos ficheros almacenan * el mismo número de datos */ template <typename T> bool igualLongitud (const char nombre1[], const char nombre2[]) { // Asocia los ficheros [nombre1] y [nombre2] a los flujos [f1] y [f2] ifstream f1, f2; f1.open(nombre1, ios::binary); f2.open(nombre2, ios::binary); // Determina si ambos ficheros almacenan un número igual de datos bool igual = igualLongitud <T> (f1, f2); // Libera los ficheros asociados a los flujos [f1] y [f2] f1.close(); f2.close(); // Devuelve el resultado de la comparación return igual; } 5 /* * Pre: [f1] y [f2] están asociados a dos ficheros binarios que * almacenan secuencias de datos de tipo T * Post: Devuelve cierto si y sólo si los ficheros asociados a f1 * y f2 almacenan, en el momento de ser invocada esta * función, un mismo número de datos no leídos */ template <typename T> bool igualLongitud (ifstream& f1, ifstream& f2) { T nuevo; f1.read(reinterpret_cast<char *>(&nuevo), sizeof(T)); f2.read(reinterpret_cast<char *>(&nuevo), sizeof(T)); if (!f1.eof() && !f2.eof()) { return igualLongitud <T> (f1, f2); // recurrencia } else { return f1.eof() && f2.eof(); // base } } 6 Problema 2. Diseñar sin bucles: /* * Pre: [nombre] es un fichero binario que almacena una * secuencia de longitud no nula de datos de tipo T * Post: Los valores de [menor] y [mayor] son iguales al menor * y al mayor, respectivamente, de los datos almacenados * en el fichero [nombre] */ template <typename T> void extremos (const char nombre[], T& menor, T& mayor); 7 /* * Pre: [nombre] es un fichero binario que almacena una secuencia de * longitud no nula de datos de tipo T * Post: Los valores de [menor] y [mayor] son iguales al menor * y al mayor, respectivamente, de los datos almacenados * en el fichero [nombre] */ template <typename T> void extremos (const char nombre[], T& menor, T& mayor); /* * Pre: [f] es un flujo asociado a un fichero binario que almacena una * secuencia de longitud no nula de datos de tipo T y los valores * de [menor] y [mayor] son iguales a los de los datos leídos con * menor valor y mayor valor, respectivamente. * Post: Los valores de [menor] y [mayor] son iguales al menor * y al mayor, respectivamente, de los datos almacenados * en el fichero asociado al flujo [f] */ template <typename T> void extremos (ifstream& f, T& menor, T& mayor); 8 /* * Pre: [nombre] es un fichero binario que almacena una * secuencia de longitud no nula de datos de tipo T * Post: Los valores de [menor] y [mayor] son iguales al menor * y al mayor, respectivamente, de los datos almacenados * en el fichero [nombre] */ template <typename T> void extremos (const char nombre[], T& menor, T& mayor) { // Asocia el ficheros binario [nombre] al flujo [f] ifstream f; f.open(nombre, ios::binary); // Asigna a [menor] y [mayor] el primer dato del fichero f.read(reinterpret_cast<char *>(&menor), sizeof(T)); mayor = menor; // Determina el menor y el mayor de los datos almacenados en el fichero extremos <T> (f, menor, mayor); // Libera el fichero asociado al flujo [f] f.close(); } 9 /* * Pre: [f] es un flujo asociado a un fichero binario que almacena una * secuencia de longitud no nula de datos de tipo T y los valores * de [menor] y [mayor] son iguales a los de los datos leídos con * menor valor y mayor valor, respectivamente. * Post: Los valores de [menor] y [mayor] son iguales al menor * y al mayor, respectivamente, de los datos almacenados * en el fichero asociado al flujo [f] */ template <typename T> void extremos (ifstream& f, T& menor, T& mayor) { T nuevo; f.read(reinterpret_cast<char *>(&nuevo), sizeof(T)); if (!f.eof()) { if (nuevo < menor) { menor = nuevo; } else if (mayor < nuevo) { mayor = nuevo; } extremos <T> (f, menor, mayor); } } 10 Problema 3. Diseñar sin bucles: /* * Pre: [nombre] es un fichero binario que almacena una * secuencia de longitud no nula de datos de tipo T * ordenada de menor a mayor valor * Post: Los valores de [menor] y [mayor] son iguales al menor * y al mayor, respectivamente, de los datos almacenados * en el fichero [nombre] */ template <typename T> void extremosV2 (const char nombre[], T& menor, T& mayor); 11 /* * Pre: [nombre] es un fichero binario que almacena una secuencia de * longitud no nula de datos de tipo T ordenada de menor a mayor valor * Post: Los valores de [menor] y [mayor] son iguales al menor y al mayor, * respectivamente, de los datos almacenados en el fichero [nombre] */ template <typename T> void extremosV2 (const char nombre[], T& menor, T& mayor); /* * Pre: [f] es un flujo asociado a un fichero binario que almacena una * secuencia de longitud no nula de datos de tipo T y el valor de * [anterior] es igual al del último dato leído del fichero * Post: Devuelve el último de los datos almacenados en el fichero * asociado al flujo [f] */ template <typename T> T ultimo (ifstream& f, T anterior); 12 /* * Pre: [nombre] es un fichero binario que almacena una secuencia de * longitud no nula de datos de tipo T ordenada de menor a mayor valor * Post: Los valores de [menor] y [mayor] son iguales al menor y al mayor, * respectivamente, de los datos almacenados en el fichero [nombre] */ template <typename T> void extremosV2 (const char nombre[], T& menor, T& mayor) { // Asocia el ficheros binario [nombre] al flujo [f] ifstream f; f.open(nombre, ios::binary); // Asigna a [menor] el primer dato del fichero f.read(reinterpret_cast<char *>(&menor), sizeof(T)); // Asigna a [mayor] el último dato del fichero mayor = ultimo <T> (f, menor); // Libera el fichero asociado al flujo [f] f.close(); } 13 /* * Pre: [f] es un flujo asociado a un fichero binario que almacena una * secuencia de longitud no nula de datos de tipo T y el valor de * [anterior] es igual al del último dato leído del fichero * Post: Devuelve el último de los datos almacenados en el fichero * asociado al flujo [f] */ template <typename T> T ultimo (ifstream& f, T anterior) { T nuevo; f.read(reinterpret_cast<char *>(&nuevo), sizeof(T)); if (!f.eof()) { return ultimo <T> (f, nuevo); } else { return anterior; } } 14 Problema 4. Diseñar sin bucles: /* * Pre: [nombre] es un fichero binario que almacena una * secuencia de datos de tipo T que cuenta, al menos, * con un dato menor que [limite] * Post: Devuelve el primero de los datos almacenados en el * fichero [nombre] cuyo valor es inferior al de [limite] */ template <typename T> T primerMenor (const char nombre[], const T limite); 15 /* * Pre: [nombre] es un fichero binario que almacena una secuencia * de datos de tipo T que cuenta, al menos, con un dato menor que * [limite] * Post: Devuelve el primero de los datos almacenados en el fichero * [nombre] cuyo valor es inferior al de [limite] */ template <typename T> T primerMenor (const char nombre[], const T limite); /* * Pre: [f] es un flujo asociado a un fichero binario que almacena una * secuencia de datos de tipo T que cuenta, al menos, con un dato * menor que [limite]. No se ha leído ningún dato de fichero cuyo * valor sea inferior al de [limite] * Post: Devuelve el primero de los datos almacenados en el fichero * asociado a [f] cuyo valor es inferior al de [limite] */ template <typename T> T primerMenor (ifstream& f, const T limite); 16 /* * Pre: [nombre] es un fichero binario que almacena una secuencia * de datos de tipo T que cuenta, al menos, con un dato menor que * [limite] * Post: Devuelve el primero de los datos almacenados en el fichero * [nombre] cuyo valor es inferior al de [limite] */ template <typename T> T primerMenor (const char nombre[], const T limite) { // Asocia el ficheros binario [nombre] al flujo [f] ifstream f; f.open(nombre, ios::binary); // Asigna a [elPrimerMenor] el primer dato del fichero cuyo valor es // inferior al de [limite] T elPrimerMenor; elPrimerMenor = primerMenor <T> (f, limite); // Libera el fichero asociado al flujo [f] f.close(); // Devuelve el valor de [elPrimerMenor] return elPrimerMenor; } 17 /* * Pre: [f] es un flujo asociado a un fichero binario que almacena una * secuencia de datos de tipo T que cuenta, al menos, con un dato * menor que [limite]. No se ha leído ningún dato de fichero cuyo * valor sea inferior al de [limite] * Post: Devuelve el primero de los datos almacenados en el fichero * asociado a [f] cuyo valor es inferior al de [limite] */ template <typename T> T primerMenor (ifstream& f, const T limite) { T nuevo; f.read(reinterpret_cast<char *>(&nuevo), sizeof(T)); if (nuevo < limite) { return nuevo; } else { return primerMenor <T> (f, limite); } } 18 Problema 5. Diseñar sin bucles: /* * Pre: [nombre] es un fichero binario que almacena una * secuencia de datos de tipo T, ordenada de menor a * mayor valor, que cuenta, al menos, con un dato menor * que [limite] * Post: Devuelve el último de los datos almacenados en el * fichero [nombre] cuyo valor es inferior al de [limite] */ template <typename T> T ultimoMenor (const char nombre[], const T limite); 19 /* * Pre: [nombre] es un fichero binario que almacena una secuencia de * datos de tipo T, , que cuenta, * al menos, con un dato menor que [limite] * Post: Devuelve el último de los datos almacenados en el fichero * [nombre] cuyo valor es inferior al de [limite] */ template <typename T> T ultimoMenor (const char nombre[], const T limite); /* * Pre: [f] es un flujo asociado a un fichero binario que almacena una * secuencia de datos de tipo T, ordenada de menor a mayor valor, * que cuenta, al menos, con un dato menor que [limite]. El último * dato leído del fichero es igual a [ultimo] y su valor es inferior * al de [limite] * Post: Devuelve el ultimo de los datos almacenados en el fichero * asociado a [f] cuyo valor es inferior al de [limite] */ template <typename T> T ultimoMenor (ifstream& f, const T limite, const T ultimo); 20 /* * Pre: [nombre] es un fichero binario que almacena una secuencia de * datos de tipo T, ordenada de menor a mayor valor, que cuenta, * al menos, con un dato menor que [limite] * Post: Devuelve el primero de los datos almacenados en el * fichero [nombre] cuyo valor es inferior al de [limite] */ template <typename T> T ultimoMenor (const char nombre[], const T limite) { // Asocia el ficheros binario [nombre] al flujo [f] ifstream f; f.open(nombre, ios::binary); // Asigna a [primero] el valor del primer dato del fichero T primero; f.read(reinterpret_cast<char *>(&primero), sizeof(T)); T elUltimoMenor; elUltimoMenor = ultimoMenor <T> (f, limite, primero); f.close(); return elUltimoMenor; } 21 /* * Pre: [f] es un flujo asociado a un fichero binario que almacena una * secuencia de datos de tipo T, ordenada de menor a mayor valor, * que cuenta, al menos, con un dato menor que [limite]. El último * dato leído del fichero es igual a [ultimo] y su valor es inferior * al de [limite] * Post: Devuelve el ultimo de los datos almacenados en el fichero * asociado a [f] cuyo valor es inferior al de [limite] */ template <typename T> T ultimoMenor (ifstream& f, const T limite, const T ultimo) { T nuevo; f.read(reinterpret_cast<char *>(&nuevo), sizeof(T)); if (!f.eof()) { if (nuevo < limite) { return ultimoMenor <T> (f, limite, nuevo); } else { return ultimo; } } else { return ultimo; } } 22 23