Programaci´
on II
Relaci´
on de Ejercicios
y Soluciones
Sonido e Imagen
UNIVERSIDAD DE M ´ALAGADpto. Lenguajes y CC. Computaci´on E.T.S.I. Telecomunicaci´on
´
Indice
Tema 1: Almacenamiento en Memoria Secundaria. Ficheros
2
Tema 2: Tipos Abstractos de Datos
15
Tema 2.1: Programacion Modular
. . . .
15
Tema 2.2: Tipos Abstractos de Datos
. . . .
24
Tema 2.3: Tipos Abstractos de Datos Gen´
ericos
. . . .
49
Tema 3: Gesti´
on de Memoria Din´
amica
74
Tema 3.1: Listas Enlazadas
. . . .
74
Tema 3.2: Abstracci´
on en la Gesti´
on de Memoria Din´
amica
. . . .
93
Tema 3.3: Genericidad en la Gesti´
on de Memoria Din´
amica
. . . .
136
Tema 4: Colecciones
147
Pr´
acticas de Laboratorio
162
Pr´
actica 1: Almacenamiento Persistente de Datos
. . . .
162
Pr´
actica 2: Tipos Abstractos de Datos
. . . .
171
Pr´
actica 3: Tipos Abstractos de Datos Gen´
ericos
. . . .
181
Pr´
actica 4: Gesti´
on de Memoria Din´
amica
. . . .
193
Pr´
actica 5: Abstracci´
on en la Gesti´
on de Memoria Din´
amica
. . . .
200
Pr´
actica 6: Biblioteca Est´
andar
. . . .
208
Problemas de Examen
214
Examen 1: Gesti´
on de Agencia de Viajes
. . . .
214
Examen 2: Juego de Ajedrez
. . . .
223
Examen 3: Gesti´
on de Hotel
. . . .
231
Nota:
en la soluci´
on a los ejercicios, se ha utilizado el tipo
array
de TR1, que ha sido incorporado a la
biblio-teca de C++ en el est´
andar de 2011. Si su biblioteca est´
andar no contiene la definici´
on del tipo
array
, puede
descargarla desde la siguiente direcci´
on:
http://www.lcc.uma.es/%7Evicente/docencia/cpplibs/array_tr1.zip
Tema 1: Almacenamiento en Memoria Secundaria. Ficheros
1. Escribir un programa que cuente el n´
umero de letras min´
usculas, de letras may´
usculas y de d´ıgitos de un
fichero.
Soluci´on #include <iostream>
#include <fstream> using namespace std; struct Estad {
unsigned may; unsigned min; unsigned dig; };
// inicializa cuenta de estadisticas void inic(Estad& sts)
{
sts.may = 0; sts.min = 0; sts.dig = 0; }
// muestra las estadisticas void escribir(const Estad& sts) {
cout << "Mayusculas: " << sts.may << endl; cout << "Minusculas: " << sts.min << endl; cout << "Digitos: " << sts.dig << endl; }
inline bool es_mayuscula(char c) {
return (c >= ’A’ && c <= ’Z’); }
inline bool es_minuscula(char c) {
return (c >= ’a’ && c <= ’z’); }
inline bool es_digito(char c) {
return (c >= ’0’ && c <= ’9’); }
void procesar(char c, Estad& sts) {
if (es_mayuscula(c)) { ++sts.may;
} else if (es_minuscula(c)) { ++sts.min;
} else if (es_digito(c)) { ++sts.dig;
} }
void estadisticas(const string& nombre, bool& ok, Estad& sts) {
ifstream fich;
fich.open(nombre.c_str()); if (fich.fail()) {
ok = false; } else {
inic(sts); char c; fich.get(c);
while (! fich.fail()) { procesar(c, sts); fich.get(c); }
}
int main() {
bool ok; Estad sts;
cout << "Introduzca el nombre del fichero: "; string nombre;
cin >> nombre;
estadisticas(nombre, ok, sts); if (ok) {
escribir(sts); } else {
cout << "Error al procesar el fichero" << endl; }
}
2. Escribir un programa con la opci´
on de encriptar y de desencriptar un fichero de texto, dependiendo de la
extensi´
on del fichero de entrada. La encriptaci´
on (codificaci´
on) consiste en que dado un fichero de texto
de entrada (extensi´
on
txt
) genere otro fichero de salida encriptado (extensi´
on
cod
). Esta codificaci´
on
consiste reemplazar cada letra por la tercera siguiente de forma circular (ej.
a
→
d
,
b
→
e
,
· · ·
,
w
→
z
,
x
→
a
,
y
→
b
,
z
→
c
). La opci´
on de desencriptado consiste en leer un fichero codificado (extensi´
on
cod
) y recuperar
la informaci´
on original en un fichero de texto (extensi´
on
txt
).
Soluci´on #include <iostream>
#include <fstream> using namespace std;
const unsigned DESPL = 3;
enum Operacion {
CIFRAR, DESCIFRAR, ERROR };
// cifrado rotacional (DESPL) de letra char cifrar(char c)
{
if (c >= ’a’ && c <= ’z’) { c = char(c + DESPL); if (c > ’z’) {
c = char(’a’ + c - ’z’ - 1); }
} else if (c >= ’A’ && c <= ’Z’) { c = char(c + DESPL);
if (c > ’Z’) {
c = char(’A’ + c - ’Z’ - 1); }
}
return c; }
// descifrado rotacional (DESPL) de letra char descifrar(char c)
{
if (c >= ’a’ && c <= ’z’) { c = char(c - DESPL); if (c < ’a’) {
c = char(’z’ + c - ’a’ + 1); }
} else if (c >= ’A’ && c <= ’Z’) { c = char(c - DESPL);
if (c < ’A’) {
c = char(’Z’ + c - ’A’ + 1); }
}
return c; }
// transforma una letra segun el codigo de operacion char transformar(char c, Operacion op)
{
char res;
res = cifrar(c); } else {
res = descifrar(c); }
return res; }
// trasnforma el fichero de entrada y lo escribe en el fichero de salida void transformar_fichero(const string& entrada, const string& salida,
Operacion op, bool& ok) {
ifstream f_ent;
f_ent.open(entrada.c_str()); if (f_ent.fail()) {
ok = false; } else {
ofstream f_sal;
f_sal.open(salida.c_str()); if (f_sal.fail()) {
ok = false; } else {
char ch; f_ent.get(ch);
while (! f_ent.fail() && ! f_sal.fail()) { f_sal.put(transformar(ch, op)); f_ent.get(ch);
}
ok = (f_ent.eof() && ! f_sal.fail()); f_sal.close();
}
f_ent.close(); }
}
// busca un caracter e una cadena
unsigned buscar(const string& nombre, char c) {
unsigned i = 0;
while ((i < nombre.size())&&(c != nombre[i])) { ++i;
}
return i; }
// devuelve la extension del nombre de fichero string extension(const string& nombre)
{
string res = "";
unsigned i = buscar(nombre, ’.’); if (i < nombre.size()) {
res = nombre.substr(i+1, nombre.size()-(i+1)); }
return res; }
// calcula la operacion a realizar a partir de las extensiones de los // ficheros de entrada y salida
Operacion codigo_op(const string& entrada, const string& salida) {
Operacion res;
if ((extension(entrada)=="txt")&&(extension(salida)=="cod")) { res = CIFRAR;
} else if ((extension(entrada)=="cod")&&(extension(salida)=="txt")) { res = DESCIFRAR;
} else { res = ERROR; }
return res; }
int main() {
bool ok;
string nombre_ent; cin >> nombre_ent;
cout << "Introduzca el nombre del fichero de salida: "; string nombre_sal;
cin >> nombre_sal;
Operacion op = codigo_op(nombre_ent, nombre_sal); if (op != ERROR) {
transformar_fichero(nombre_ent, nombre_sal, op, ok); if (ok) {
cout << "Procesamiento correcto" << endl; } else {
cout << "Error al procesar el fichero" << endl; }
} else {
cout << "Error: extensiones erroneas" << endl; }
}
3. Escribir un programa para procesar informaci´
on sobre los clientes de una agencia matrimonial. El programa
debe crear un fichero de texto (cuyo nombre se leer´
a por teclado) en el que se guarde la informaci´
on de
un n´
umero indeterminado de personas. La informaci´
on que se guardar´
a por cada persona ser´
a:
Nombre:
Cadena de caracteres.
Edad
int
.
G´
enero
char
(M/F).
Arte
char
(S/N).
Deporte
char
(S/N).
Libros
char
(S/N).
M´
usica
char
(S/N).
La informaci´
on correspondiente a cada persona se leer´
a del teclado. El proceso finalizar´
a cuando se teclee
un campo
Nombre
que est´
e vac´ıo.
Soluci´on #include <iostream>
#include <fstream> #include <string> #include <tr1/array> using namespace std; using namespace std::tr1;
enum Genero {
FEMENINO, MASCULINO };
const unsigned NAFICCIONES = 4;
typedef array<string, NAFICCIONES> StrAficciones; const StrAficciones AFICCIONES = {{
"Arte", "Deporte", "Libros", "Musica" }};
typedef array<bool, NAFICCIONES> Aficciones;
struct Persona { string nombre; unsigned edad; Genero gen; Aficciones af; };
//---// convierte una letra a mayusculas inline char mayuscula(char c) {
if (c >= ’a’ && c <= ’z’) { c = char(c - ’a’ + ’A’); }
return c; }
//---// leer una opcion (S/N) a bool inline void leer(bool& a) {
char c; cin >> c;
a = (mayuscula(c) == ’S’); }
// leer el genero (M/F) a tipo enumerado inline void leer(Genero& g)
{
char c; cin >> c;
if (mayuscula(c) == ’M’) { g = MASCULINO;
} else {
g = FEMENINO; }
}
// leer aficciones void leer(Aficciones& af) {
for (unsigned i = 0; i < af.size(); ++i) { cout << AFICCIONES[i] << " (S/N): "; leer(af[i]);
} }
// leer datos de persona void leer(Persona& p) {
cout << "Nombre: "; getline(cin, p.nombre); if (p.nombre.size() > 0) {
cout << "Edad: "; cin >> p.edad;
cout << "Genero (M/F): "; leer(p.gen);
leer(p.af);
cin.ignore(1000, ’\n’); }
}
//---//-- Escribir a Fichero --- //---// escribir una opcion (S/N) bool a fichero
inline void escribir(ofstream& fich, bool a) {
if (a) { fich << ’S’; } else {
fich << ’N’; }
}
// escribir el genero (M/F) tipo enumerado a fichero inline void escribir(ofstream& fich, Genero g) {
if (g == MASCULINO) { fich << ’M’; } else {
fich << ’F’; }
}
// escribir una persona a fichero
void escribir(ofstream& fich, const Persona& p) {
fich << p.nombre << endl; fich << p.edad << " " ; escribir(fich, p.gen);
for (unsigned i = 0; i < p.af.size(); ++i) { escribir(fich, p.af[i]);
fich << endl; }
void crear_fichero(const string& nombre, bool& ok) {
ofstream fich;
fich.open(nombre.c_str()); if (fich.fail()) {
ok = false; } else {
Persona p; leer(p);
while ( !cin.fail() && (p.nombre.size() > 0)&& ! fich.fail()) { escribir(fich, p);
leer(p); }
ok = !cin.fail() && ! fich.fail(); fich.close();
} }
int main() {
bool ok;
cout << "Introduzca el nombre del fichero: "; string nombre;
cin >> nombre;
cin.ignore(1000, ’\n’); crear_fichero(nombre, ok); if (ok) {
cout << "Procesamiento correcto" << endl; } else {
cout << "Error al procesar el fichero" << endl; }
}
4. Ampliar el programa que procesa clientes de una agencia matrimonial para que tome los datos de todos los
candidatos a estudiar del fichero del ejercicio anterior, lea el cliente del teclado y finalmente genere como
resultado un fichero (cuyo nombre ser´
a le´ıdo desde teclado) con toda la informaci´
on correspondiente a los
candidatos aceptados. Una persona del fichero de entrada se considerar´
a aceptable como candidato si tiene
diferente g´
enero y por lo menos tres aficiones comunes con respecto al aspirante introducido por pantalla.
(El programa debe ser capaz de trabajar con cualquier n´
umero de personas en el fichero de entrada).
Soluci´on #include <iostream>
#include <fstream> #include <string> #include <tr1/array> using namespace std; using namespace std::tr1;
enum Genero {
FEMENINO, MASCULINO };
const unsigned NAFICCIONES = 4;
typedef array<string, NAFICCIONES> StrAficciones; const StrAficciones AFICCIONES = {{
"Arte", "Deporte", "Libros", "Musica" }};
typedef array<bool, NAFICCIONES> Aficciones;
const unsigned NAFICCOMP = 3;
struct Persona { string nombre; unsigned edad; Genero gen; Aficciones af; };
inline char mayuscula(char c) {
if (c >= ’a’ && c <= ’z’) { c = char(c - ’a’ + ’A’); }
return c; }
//---//-- Leer de Teclado --- //---// leer una opcion (S/N) a bool
inline void leer(bool& a) {
char c; cin >> c;
a = (mayuscula(c) == ’S’); }
// leer el genero (M/F) a tipo enumerado inline void leer(Genero& g)
{
char c; cin >> c;
if (mayuscula(c) == ’M’) { g = MASCULINO;
} else {
g = FEMENINO; }
}
// leer aficciones void leer(Aficciones& af) {
for (unsigned i = 0; i < af.size(); ++i) { cout << AFICCIONES[i] << " (S/N): "; leer(af[i]);
} }
// leer datos de persona void leer(Persona& p) {
cout << "Nombre: "; getline(cin, p.nombre); if (p.nombre.size() > 0) {
cout << "Edad: "; cin >> p.edad; cout << "Genero: "; leer(p.gen); leer(p.af);
cin.ignore(1000, ’\n’); }
}
//---//-- Leer de Fichero --- //---// leer una opcion (S/N) a bool
inline void leer(ifstream& in, bool& a) {
char c; in >> c;
a = (mayuscula(c) == ’S’); }
// leer el genero (M/F) a tipo enumerado inline void leer(ifstream& in, Genero& g) {
char c; in >> c;
if (mayuscula(c) == ’M’) { g = MASCULINO;
} else {
} }
// leer datos de persona
void leer(ifstream& in, Persona& p) {
getline(in, p.nombre); in >> p.edad;
leer(in, p.gen);
for (unsigned i = 0; i < p.af.size(); ++i) { leer(in, p.af[i]);
}
in.ignore(1000, ’\n’); }
//---//-- Escribir a Fichero --- //---// escribir una opcion (S/N) bool a fichero
inline void escribir(ofstream& fich, bool a) {
if (a) { fich << ’S’; } else {
fich << ’N’; }
}
// escribir el genero (M/F) tipo enumerado a fichero inline void escribir(ofstream& fich, Genero g) {
if (g == MASCULINO) { fich << ’M’; } else {
fich << ’F’; }
}
// escribit una persona a fichero
void escribir(ofstream& fich, const Persona& p) {
fich << p.nombre << endl; fich << p.edad << " " ; escribir(fich, p.gen);
for (unsigned i = 0; i < p.af.size(); ++i) { escribir(fich, p.af[i]);
}
fich << endl; }
//---// dos personas son compatibles si sus aficciones comunes superan un // determinado umbral
bool es_compatible(const Persona& p1, const Persona& p2) {
unsigned cnt = 0;
for (unsigned i = 0; i < p1.af.size(); ++i) { if (p1.af[i] == p2.af[i]) {
++cnt; }
}
return (p1.gen != p2.gen) && (cnt >= NAFICCOMP); }
//---void procesar_fichero(const string& nombre_ent, const string& nombre_sal,
const Persona& pers, bool& ok) {
ifstream fich_ent;
fich_ent.open(nombre_ent.c_str()); if (fich_ent.fail()) {
ok = false; } else {
ofstream fich_sal;
fich_sal.open(nombre_sal.c_str()); if (fich_sal.fail()) {
ok = false; } else {
leer(fich_ent, p);
while ( ! fich_ent.fail() && ! fich_sal.fail()) { if (es_compatible(pers, p)) {
escribir(fich_sal, p); }
leer(fich_ent, p); }
ok = fich_ent.eof() && ! fich_sal.fail(); fich_sal.close();
}
fich_ent.close(); }
}
//---int main()
{
bool ok;
cout << "Introduzca el nombre del fichero de entrada: "; string nombre_ent;
cin >> nombre_ent;
cout << "Introduzca el nombre del fichero de salida: "; string nombre_sal;
cin >> nombre_sal; cin.ignore(1000, ’\n’);
cout << "Introduzca datos de la persona: "; Persona pers;
leer(pers);
if (pers.nombre.size() > 0) {
procesar_fichero(nombre_ent, nombre_sal, pers, ok); if (ok) {
cout << "Procesamiento correcto" << endl; } else {
cout << "Error al procesar el fichero" << endl; }
} }
5. Codifique un programa que cree un fichero para contener los datos relativos a los art´ıculos de un almac´
en.
Para cada art´ıculo habr´
a de guardar la siguiente informaci´
on:
C´
odigo del art´ıculo
Num´
erico
Nombre del art´ıculo
Cadena de caracteres
Existencias
Num´
erico
Precio
Num´
erico
Se deber´
a pedir datos de cada art´ıculo por teclado hasta que se teclee 0 (cero) como c´
odigo de art´ıculo.
Soluci´on #include <iostream>
#include <fstream> #include <string> using namespace std;
struct Articulo { unsigned codigo; string nombre; unsigned existencias; unsigned precio; };
// leer articulo desde el teclado void leer(Articulo& a)
{
cout << "Codigo de articulo: "; cin >> a.codigo;
if (a.codigo != 0) {
cout << "Nombre de articulo: ";
cin >> ws; // salta separadores del codigo de articulo getline(cin, a.nombre);
}
// escribe articulo a fichero
void escribir(ofstream& fich, const Articulo& a) {
fich << a.codigo << " " << a.nombre << endl; fich << a.existencias << " " << a.precio << endl; }
// lee articulos y los escribe en el fichero void crear_fichero(const string& nombre, bool& ok) {
ofstream fich;
fich.open(nombre.c_str()); if (fich.fail()) {
ok = false; } else {
Articulo a; leer(a);
while ( !cin.fail() && (a.codigo != 0)&& ! fich.fail()) { escribir(fich, a);
leer(a); }
ok = !cin.fail() && ! fich.fail(); fich.close();
} }
int main() {
bool ok;
cout << "Introduzca el nombre del fichero: "; string nombre;
cin >> nombre;
cin.ignore(1000, ’\n’); crear_fichero(nombre, ok); if (ok) {
cout << "Procesamiento correcto" << endl; } else {
cout << "Error al procesar el fichero" << endl; }
}
6. Escriba un programa que tome como entrada el fichero del ejercicio anterior y una condici´
on sobre los
campos
existencias
o
precio
. La condici´
on podr´
a ser:
<
campo
>
[
<
,
<
=,
>
,
>
=, ==, ! =]
<
n´
umero
>
Este programa debe generar como salida un fichero que contenga todos aquellos art´ıculos para los que se
cumple la condici´
on de entrada.
Soluci´on #include <iostream>
#include <fstream> #include <string> using namespace std;
enum Campo {
EXISTENCIAS, PRECIO };
enum Cmp {
MENOR, MENIG, MAYOR, MAYIG, IGUAL, DISTINTO };
struct Condicion { Campo campo; Cmp cmp; unsigned num; };
// convierte a mayusculas inline char mayuscula(char c) {
if (c >= ’a’ && c <= ’z’) { c = char(c - ’a’ + ’A’); }
return c; }
//---//-- Leer de Teclado --- //---// lee el campo por el que realizar la comparacion
inline void leer(Campo& c, bool& ok) {
string s; cin >> s; ok = true;
if (s == "existencia") { c = EXISTENCIAS; } else if (s == "precio") {
c = PRECIO; } else {
ok = false; }
}
// lee el codigo de comparacion inline void leer(Cmp& c, bool& ok) {
string s; cin >> s; ok = true; if (s == "<") {
c = MENOR;
} else if (s == "<=") { c = MENIG;
} else if (s == ">") { c = MAYOR;
} else if (s == ">=") { c = MAYIG;
} else if (s == "==") { c = IGUAL;
} else if (s == "!=") { c = DISTINTO; } else {
ok = false; }
}
// lee la condicion de procesamiento (campo y comparacion) inline void leer(Condicion& c, bool& ok)
{
bool ok1, ok2;
cout << "Introduzca campo: (existencia, precio) "; leer(c.campo, ok1);
cout << "Introduzca comparacion: (< <= > >= == !=) "; leer(c.cmp, ok2);
cout << "Introduzca numero: "; cin >> c.num;
ok = ok1 && ok2; }
//---//-- Leer de Fichero --- //---// lee un articulo de fichero
void leer(ifstream& in, Articulo& a) {
in >> a.codigo; in >> ws;
}
//---//-- Escribir a Fichero --- //---// escribe articulo a fichero
void escribir(ofstream& fich, const Articulo& a) {
fich << a.codigo << " " << a.nombre << endl; fich << a.existencias << " " << a.precio << endl; }
//---// comprueba si un articulo es compatible con la condicion de comparacion bool es_compatible(const Articulo& a, const Condicion& c)
{
unsigned valor = 0; switch (c.campo) {
case EXISTENCIAS: valor = a.existencias; break; case PRECIO: valor = a.precio; break; }
bool res = false; switch (c.cmp) {
case MENOR: res = valor < c.num; break; case MENIG: res = valor <= c.num; break; case MAYOR: res = valor > c.num; break; case MAYIG: res = valor >= c.num; break; case IGUAL: res = valor == c.num; break; case DISTINTO: res = valor != c.num; break; }
return res; }
//---// lee articulos de fichero y escribe en otro fichero aquellos que son // compatibles con un codigo de comparacion
void procesar_fichero(const string& nombre_ent, const string& nombre_sal, const Condicion& c, bool& ok)
{
ifstream fich_ent;
fich_ent.open(nombre_ent.c_str()); if (fich_ent.fail()) {
ok = false; } else {
ofstream fich_sal;
fich_sal.open(nombre_sal.c_str()); if (fich_sal.fail()) {
ok = false; } else {
Articulo a; leer(fich_ent, a);
while ( ! fich_ent.fail() && ! fich_sal.fail()) { if (es_compatible(a, c)) {
escribir(fich_sal, a); }
leer(fich_ent, a); }
ok = fich_ent.eof() && ! fich_sal.fail(); fich_sal.close();
}
fich_ent.close(); }
}
//---int main()
{
bool ok;
cout << "Introduzca el nombre del fichero de entrada: "; string nombre_ent;
cin >> nombre_ent;
cout << "Introduzca el nombre del fichero de salida: "; string nombre_sal;
cin >> nombre_sal; cin.ignore(1000, ’\n’);
cout << "Introduzca la condicion de procesamiento: " << endl; Condicion c;
if (ok) {
procesar_fichero(nombre_ent, nombre_sal, c, ok); if (ok) {
cout << "Procesamiento correcto" << endl; } else {
cout << "Error al procesar el fichero" << endl; }
Tema 2: Tipos Abstractos de Datos
Tema 2.1: Programacion Modular
Dise˜
ne e implemente los siguientes M´
odulos, dentro del espacio de nombres
umalcc
, as´ı como programas de
utilizaci´
on que permitan comprobar su funcionamiento.
1. Dise˜
ne un m´
odulo que proporcione soporte adecuado a la ar´ımetica con n´
umeros complejos. El m´
odulo
deber´
a definir el tipo
Complejo
, as´ı como los siguientes subprogramas:
Soluci´on: complejos.hpp #ifndef _complejos_hpp_
#define _complejos_hpp_ namespace umalcc {
//---const double ERROR_PRECISION = 1e-6 ; //---struct Complejo {
double real ; // parte real del numero complejo double imag ; // parte imaginaria del numero complejo } ;
//---void sumar(Complejo& r, const Complejo& a, const Complejo& b) ; // Devuelve un numero complejo (r) que contiene el resultado de // sumar los numeros complejos (a) y (b).
//---void restar(Complejo& r, const Complejo& a, const Complejo& b) ; // Devuelve un numero complejo (r) que contiene el resultado de // restar los numeros complejos (a) y (b).
//---void multiplicar(Complejo& r, const Complejo& a, const Complejo& b) ; // Devuelve un numero complejo (r) que contiene el resultado de // multiplicar los numeros complejos (a) y (b).
//---void dividir(Complejo& r, const Complejo& a, const Complejo& b) ; // Devuelve un numero complejo (r) que contiene el resultado de // dividir los numeros complejos (a) y (b).
//---bool iguales(const Complejo& a, const Complejo& b) ;
// Devuelve true si los numeros complejos (a) y (b) son iguales.
//---void escribir(const Complejo& a) ;
// muestra en pantalla el numero complejo (a)
//---void leer(Complejo& a) ;
// lee de teclado el valor del numero complejo (a). // lee la parte real y la parte imaginaria del numero
//---} #endif
Soluci´on: complejos.cpp #include "complejos.hpp"
#include <iostream> using namespace std ; using namespace umalcc ;
//---// Espacio de nombres anonimo. Es una parte privada de la
// implementacion. No es accesible desde fuera del modulo
//---namespace {
//---//-- Subprogramas Auxiliares --- //---// cuadrado de un numero (a^2) inline double sq(double a) {
return a*a ; }
{
if (a < 0) { a = -a ; }
return a ; }
//---// Dos numeros reales son iguales si la distancia que los // separa es lo suficientemente pequenya
inline bool iguales(double a, double b) {
return abs(a-b) <= ERROR_PRECISION ; }
}
//---// Espacio de nombres umalcc.
// Aqui reside la implementacion de la parte publica del modulo
//---namespace umalcc {
//---//-- Implementaci´on ---
//---// Devuelve un numero complejo (r) que contiene el resultado de // sumar los numeros complejos (a) y (b).
void sumar(Complejo& r, const Complejo& a, const Complejo& b) {
r.real = a.real + b.real ; r.imag = a.imag + b.imag ; }
//---// Devuelve un numero complejo (r) que contiene el resultado de // restar los numeros complejos (a) y (b).
void restar(Complejo& r, const Complejo& a, const Complejo& b) {
r.real = a.real - b.real ; r.imag = a.imag - b.imag ; }
//---// Devuelve un numero complejo (r) que contiene el resultado de // multiplicar los numeros complejos (a) y (b).
void multiplicar(Complejo& r, const Complejo& a, const Complejo& b) {
double p_real = (a.real * b.real) - (a.imag * b.imag) ; double p_imag = (a.real * b.imag) + (a.imag * b.real) ; r.real = p_real;
r.imag = p_imag; }
//---// Devuelve un numero complejo (r) que contiene el resultado de // dividir los numeros complejos (a) y (b).
void dividir(Complejo& r, const Complejo& a, const Complejo& b) {
double divisor = sq(b.real) + sq(b.imag) ; if (::iguales(0.0, divisor)) {
r.real = 0 ; r.imag = 0 ; } else {
double p_real = ((a.real * b.real) + (a.imag * b.imag)) / divisor ; double p_imag = ((a.imag * b.real) - (a.real * b.imag)) / divisor ; r.real = p_real;
r.imag = p_imag; }
}
//---// Devuelve true si los numeros complejos (a) y (b) son iguales. bool iguales(const Complejo& a, const Complejo& b)
{
return ::iguales(a.real, b.real) && ::iguales(a.imag, b.imag) ; }
//---// muestra en pantalla el numero complejo (a) void escribir(const Complejo& a)
{
//---// lee de teclado el valor del numero complejo (a). // lee la parte real y la parte imaginaria del numero void leer(Complejo& a)
{
cin >> a.real >> a.imag ; }
//---}
Soluci´on: main.cpp #include <iostream>
#include "complejos.hpp" using namespace std ; using namespace umalcc ;
//---void leer(Complejo& c)
{
cout << "Introduzca un numero complejo { real img }: " ; // cualificacion expl´ıcita del espacio de nombres uamalcc // para evitar colisi´on en invocaci´on a subprograma // leer(Complejo& c) del espacio de nombres umalcc umalcc::leer(c) ;
}
//---void prueba_suma(const Complejo& c1, const Complejo& c2) {
Complejo c0 ; sumar(c0, c1, c2) ; escribir(c1) ; cout <<" + " ; escribir(c2) ; cout <<" = " ; escribir(c0) ; cout << endl ; Complejo aux ; restar(aux, c0, c2) ; if (! iguales(c1, aux)) {
cout << "Error en operaciones de suma/resta"<< endl ; }
}
//---void prueba_resta(const Complejo& c1, const Complejo& c2) {
Complejo c0 ; restar(c0, c1, c2) ; escribir(c1) ; cout <<" - " ; escribir(c2) ; cout <<" = " ; escribir(c0) ; cout << endl ; Complejo aux ; sumar(aux, c0, c2) ; if (! iguales(c1, aux)) {
cout << "Error en operaciones de suma/resta"<< endl ; }
}
//---void prueba_mult(const Complejo& c1, const Complejo& c2) {
Complejo c0 ;
multiplicar(c0, c1, c2) ; escribir(c1) ;
cout <<" * " ; escribir(c2) ; cout <<" = " ; escribir(c0) ; cout << endl ; Complejo aux ;
dividir(aux, c0, c2) ; if (! iguales(c1, aux)) {
}
//---void prueba_div(const Complejo& c1, const Complejo& c2) {
Complejo c0 ; dividir(c0, c1, c2) ; escribir(c1) ; cout <<" / " ; escribir(c2) ; cout <<" = " ; escribir(c0) ; cout << endl ; Complejo aux ;
multiplicar(aux, c0, c2) ; if (! iguales(c1, aux)) {
cout << "Error en operaciones de mult/div"<< endl ; }
}
//---int main()
{
Complejo c1, c2 ;
// cualificaci´on expl´ıcita del espacio de nombres global // para evitar colisi´on en invocaci´on al subprograma // leer(Complejo& c) del espacio de nombres global ::leer(c1) ;
::leer(c2) ;
//---prueba_suma(c1, c2) ;
prueba_resta(c1, c2) ; prueba_mult(c1, c2) ; prueba_div(c1, c2) ;
//---}
2. Dise˜
ne un m´
odulo que proporcione soporte adecuado a la ar´ımetica con n´
umeros racionales. El m´
odulo
deber´
a definir el tipo
Racional
, as´ı como los subprogramas adecuados teniendo en cuenta las siguientes
consideraciones:
Los n´
umeros racionales se representan mediante fracciones, donde tanto el numerador como
denom-inador son de tipo
int
).
Las fracciones se representar´
an en todo momento normalizadas (simplificadas):
•
Es recomendable implementar un subprograma privado de simplificaci´
on de la fracci´
on mediante
el c´
alculo del m´
aximo com´
un divisor (m.c.d.) del numerador y el denominador y su posterior
divisi´
on por dicho m.c.d.
•
Para simplificar la determinaci´
on del signo de la fracci´
on puede asumirse que el denominador de
la fracci´
on es siempre positivo (por lo que una fracci´
on de signo negativo tendr´
a un numerador
de signo negativo y un denominador de signo positivo).
El n´
umero cero se guardar´
a siempre en su forma can´
onica 0/1.
Debe evitarse en todo momento la asignaci´
on de cero a un denominador.
Debe proporcionar subprogramas para leer, escribir, sumar, restar, multiplicar y dividir fracciones.
Pueden tambi´
en suministrarse m´
etodos para comparaci´
on de n´
umeros racionales (iguales, menor,
etc).
Soluci´on: racionales.hpp #ifndef _racionales_hpp_
#define _racionales_hpp_ namespace umalcc {
//---struct Racional {
int num; // numerador int denom; // denominador };
//---void sumar(Racional& r, const Racional& r1, const Racional& r2); // Asigna al n´umero racional (r) el resultado de
//---void restar(Racional& r, const Racional& r1, const Racional& r2); // Asigna al n´umero racional (r) el resultado de
// restar los n´umeros racionales (r1) y (r2)
//---void multiplicar(Racional& r, const Racional& r1, const Racional& r2); // Asigna al n´umero racional (r) el resultado de
// multiplicar los n´umeros racionales (r1) y (r2)
//---void dividir(Racional& r, const Racional& r1, const Racional& r2); // Asigna al n´umero racional (r) el resultado de
// dividir los n´umeros racionales (r1) y (r2)
//---void escribir(const Racional& r);
// Muestra en pantalla el valor del n´umero racional (r)
//---void leer(Racional& r);
// Lee de teclado el valor del n´umero racional (r)
//---bool igual(const Racional& r1, const Racional& r2); // Devuelve true si el n´umero racional (r1) es igual a (r2)
//---bool menor(const Racional& r1, const Racional& r2);
// Devuelve true si el n´umero racional (r1) es menor que (r2) //---}
#endif
Soluci´on: racionales.cpp #include "racionales.hpp"
#include <iostream> using namespace std; using namespace umalcc ;
//---// Espacio de nombres anonimo. Es una parte privada de la
// implementacion. No es accesible desde fuera del modulo
//---namespace {
//---//-- Subprogramas Auxiliares --- //---// valor absoluto de un numero entero inline int abs(int x)
{
if (x < 0) { x = -x; }
return x; }
//---// maximo comun divisor. algoritmo de euclides int mcd(int a, int b)
{
a = abs(a); b = abs(b); int res; if (a == 0) {
res = b; } else {
while (b != 0) { if (a > b) { a = a - b; } else {
b = b - a; }
} res = a; }
return res; }
//---// minimo comun multiplo
// a = abs(a); // b = abs(b);
// return (a / mcd(a, b)) * b; // }
//---// normalizar un numero racional void normalizar(Racional& r) {
if (r.denom == 0) {
// Error denominador cero r.num = 0;
r.denom = 0; } else if (r.num == 0) {
// Forma canonica r.num = 0; r.denom = 1; } else {
// dividir numerador y denominador por MCD int max_com_div = mcd(r.num, r.denom); r.num /= max_com_div;
r.denom /= max_com_div;
// si denominador negativo, entonces cambiar signo if (r.denom < 0) {
r.num = -r.num; r.denom = -r.denom; }
} }
//---}
//---// Espacio de nombres umalcc.
// Aqui reside la implementacion de la parte publica del modulo
//---namespace umalcc {
//---void sumar(Racional& r, const Racional& r1, const Racional& r2) {
//---// n1 n2 n1*d2 n2*d1 (n1*d2)+(n2*d1) // ---- + ---- == --- + --- == ---// d1 d2 d1*d2 d2*d1 d1*d2
//---r.num = ((r1.num * r2.denom) + (r2.num * r1.denom)); r.denom = r1.denom * r2.denom;
normalizar(r); }
//---void restar(Racional& r, const Racional& r1, const Racional& r2) {
//---// n1 n2 n1*d2 n2*d1 (n1*d2)-(n2*d1) // ---- - ---- == --- - --- == ---// d1 d2 d1*d2 d2*d1 d1*d2
//---r.num = ((r1.num * r2.denom) - (r2.num * r1.denom)); r.denom = r1.denom * r2.denom;
normalizar(r); }
//---void multiplicar(Racional& r, const Racional& r1, const Racional& r2) {
//---// n1 n2 n1*n2 // ---- * ---- == ---// d1 d2 d1*d2 //---r.num = r1.num * r2.num; r.denom = r1.denom * r2.denom; normalizar(r);
}
//---// n1 n2 n1*d2 // ---- / ---- == ---// d1 d2 d1*n2 //---int p_num = r1.num * r2.denom; int p_denom = r1.denom * r2.num; r.num = p_num;
r.denom = p_denom; normalizar(r); }
//---void escribir(const Racional& r) {
if (r.denom == 0) { cout << "Error"; } else {
cout << r.num << " / " << r.denom; }
}
//---void leer(Racional& r)
{
cin >> r.num >> r.denom; normalizar(r);
}
//---bool igual(const Racional& r1, const Racional& r2) {
// ambos numeros estan normalizados
return (r1.num == r2.num && r1.denom == r2.denom); }
//---bool menor(const Racional& r1, const Racional& r2) {
//---// n1 n2 n1*d2 n2*d1 (n1*d2) < (n2*d1) // ---- < ---- ==> --- < --- ==> ---// d1 d2 d1*d2 d2*d1 d1*d2
//---return (r1.num * r2.denom) < (r2.num * r1.denom); }
//---}
Soluci´on: main.cpp #include <iostream>
#include <string> #include <cassert> #include "racionales.hpp" using namespace std; using namespace umalcc;
void escribir(const string& msj, const Racional& r) {
cout << msj; escribir(r); cout << endl; }
int main() {
//---cout << "Introduzca numerador y denominador: "; Racional r1;
leer(r1);
escribir("R1: ", r1);
//---cout << "Introduzca numerador y denominador: "; Racional r2;
leer(r2);
escribir("R2: ", r2); //---Racional r3;
escribir("R3 (r1 + r2): ", r3); //---Racional r4;
restar(r4, r3, r2);
escribir("R4 (r3 - r2): ", r4); if ( ! igual(r1, r4)) {
cout << "Error en suma/resta"<<endl; }
//---Racional r5;
multiplicar(r5, r1, r2); escribir("R5 (r1 * r2): ", r5); //---Racional r6;
dividir(r6, r5, r2);
escribir("R6 (r5 / r2): ", r6); if ( ! igual(r1, r6)) {
cout << "Error en multiplicacion/division"<<endl; }
//---}
3. Dise˜
ne un m´
odulo que proporcione soporte adecuado a la manipulaci´
on de polinomios de grados positivos
menores que 100. El m´
odulo deber´
a definir el tipo
Polinomio
, as´ı como las siguientes operaciones:
Soluci´on: polinomios.hpp #ifndef _polinomio_hpp_
#define _polinomio_hpp_ #include <iostream> #include <tr1/array> namespace umalcc {
//---const double ERROR_PRECISION = 1e-6; const unsigned MAX = 100;
typedef std::tr1::array<double, MAX> Datos; struct Polinomio {
unsigned mg; // maximo grado del polinomio
Datos coef; // coeficientes del polinomio (indice es el exp. de la X) };
//---double evaluar(const Polinomio& a, //---double x); // Devuelve el resultado de evaluar el polinomio (a) // para un valor de (x) especificado como parametro void derivar(Polinomio& r, const Polinomio& a);
// Devuelve un polinomio (r) que contiene el resultado de // calcular la derivada del polinomio (a)
void sumar(Polinomio& r, const Polinomio& a, const Polinomio& b); // Devuelve un polinomio (r) que contiene el resultado de
// sumar los polinomios (a) y (b) void escribir(const Polinomio& a) ;
// Muestra en pantalla el contenido del polinomio (a) void leer(Polinomio& a) ;
// Lee de teclado el valor del polinomio (a)
// Lee pares de coeficiente y grado hasta que el coeficiente sea cero }
#endif
Soluci´on: polinomios.cpp #include "polinomios.hpp"
#include <iostream> #include <cassert> using namespace std; using namespace umalcc ;
//---// Espacio de nombres anonimo. Es una parte privada de la
// implementacion. No es accesible desde fuera del modulo
//---namespace {
inline double abs(double a) { return (a >= 0) ? a : -a; }
//---// Dos numeros reales son iguales si la distancia que los // separa es lo suficientemente pequenya
inline bool iguales(double a, double b) { return abs(a-b) <= ERROR_PRECISION; }
//---double potencia(//---double base, unsigned exp) {
double res = 1;
for (unsigned i = 0; i < exp; ++i) { res *= base;
}
return res; }
//---void inicializar(Polinomio& a) {
a.mg = 0;
for (unsigned i = 0; i < a.coef.size(); ++i) { a.coef[i] = 0.0;
} } }
//---// Espacio de nombres umalcc.
// Aqui reside la implementacion de la parte publica del modulo
//---namespace umalcc {
//---double evaluar(const Polinomio& a, //---double x)
{
// Devuelve el resultado de evaluar el polinomio (a) // para un valor de (x) especificado como parametro double res = 0;
for (unsigned i = 0; i <= a.mg; ++i) { res += a.coef[i] * potencia(x, i); }
return res; }
void derivar(Polinomio& r, const Polinomio& a) {
assert(&r != &a);
// Devuelve un polinomio (r) que contiene el resultado de // calcular la derivada del polinomio (a)
inicializar(r);
for (unsigned i = 1; i <= a.mg; ++i) { r.coef[i-1] = a.coef[i]*i; }
r.mg = a.mg-1; }
void sumar(Polinomio& r, const Polinomio& a, const Polinomio& b) {
assert((&r != &a)&&(&r != &b));
// Devuelve un polinomio (r) que contiene el resultado de // sumar los polinomios (a) y (b)
inicializar(r); if (a.mg >= b.mg) {
r.mg = a.mg; } else {
r.mg = b.mg; }
for (unsigned i = 0; i <= r.mg; ++i) { r.coef[i] = a.coef[i] + b.coef[i]; }
}
void escribir(const Polinomio& a) {
// Muestra en pantalla el contenido del polinomio (a) for (unsigned i = 0; i <= a.mg; ++i) {
cout << (a.coef[i] > 0.0 ? " +" : " ") << a.coef[i] << " X^" << i ; }
} }
void leer(Polinomio& a) {
// Lee de teclado el valor del polinomio (a)
// Lee pares de coeficiente y grado hasta que el coeficiente sea cero inicializar(a);
double c;
cout << "Introduzca coeficiente [0 -> fin]: "; cin >> c;
while ( !cin.fail() && ! iguales(c, 0.0) ) { unsigned e;
cout << "Introduzca exponente: "; cin >> e;
if ( ! cin.fail() && (e < a.coef.size())) { a.coef[e] = c;
if (e > a.mg) { a.mg = e; }
}
cout << "Introduzca coeficiente [0 -> fin]: "; cin >> c;
} }
//---}
Soluci´on: main.cpp #include <iostream>
#include "polinomios.hpp" using namespace std; using namespace umalcc;
void escribir(const string& msj, const Polinomio& p) {
cout << msj; escribir(p); cout << endl; }
int main() {
Polinomio p1, p2, p3; leer(p1);
escribir("P1: ", p1);
cout << "P1(2) = " << evaluar(p1, 2.0) << endl; derivar(p2, p1);
escribir("P2: ", p2); sumar(p3, p1, p2); escribir("P3: ", p3); }
Tema 2.2: Tipos Abstractos de Datos
Dise˜
ne e implemente los siguientes TADs, dentro del espacio de nombres
umalcc
, as´ı como programas de
utilizaci´
on que permitan comprobar su funcionamiento.
1. TAD n´
umero complejo que defina los siguientes m´
etodos p´
ublicos:
Soluci´on: complejo.hpp #ifndef _complejos_hpp_
#define _complejos_hpp_ namespace umalcc {
//---const double ERROR_PRECISION = 1e-6 ; //---class Complejo {
//---//-- M´etodos P´ublicos ---
//---Complejo() ; // Constructor por Defecto
//---double parte_real() const ;
// devuelve la parte real del numero complejo
//---double parte_imag() const ;
// devuelve la parte imaginaria del numero complejo
//---void sumar(const Complejo& a, const Complejo& b) ; // asigna al numero complejo (actual) el resultado de // sumar los numeros complejos (a) y (b).
//---void restar(const Complejo& a, const Complejo& b) ; // asigna al numero complejo (actual) el resultado de // restar los numeros complejos (a) y (b).
//---void multiplicar(const Complejo& a, const Complejo& b) ; // asigna al numero complejo (actual) el resultado de // multiplicar los numeros complejos (a) y (b).
//---void dividir(const Complejo& a, const Complejo& b) ; // asigna al numero complejo (actual) el resultado de // dividir los numeros complejos (a) y (b).
//---bool igual(const Complejo& b) const ;
// Devuelve true si el numero complejo (actual) es // igual al numero complejo (b)
//---void escribir() const ;
// muestra en pantalla el numero complejo (actual)
//---void leer() ;
// lee de teclado el valor del numero complejo (actual). // lee la parte real y la parte imaginaria del numero
//---private:
//---//-- Atributos Privados --- //---double real ; // parte real del numero complejo
double imag ; // parte imaginaria del numero complejo //---} ;
} #endif
Soluci´on: complejo.cpp #include "complejos.hpp"
#include <iostream> using namespace std ; using namespace umalcc ;
//---// Espacio de nombres anonimo. Es una parte privada de la
// implementacion. No es accesible desde fuera del modulo
//---namespace {
//---//-- Subprogramas Auxiliares --- //---// cuadrado de un numero (a^2)
inline double sq(double a) {
return a*a ; }
//---// Valor absoluto de un numero inline double abs(double a) {
return (a >= 0) ? a : -a ; }
//---// Dos numeros reales son iguales si la distancia que los // separa es lo suficientemente pequenya
inline bool iguales(double a, double b) {
return abs(a-b) <= ERROR_PRECISION ; }
}
//---// Espacio de nombres umalcc.
// Aqui reside la implementacion de la parte publica del modulo
//---namespace umalcc {
//---//-- M´etodos P´ublicos ---
//---Complejo::Complejo() // Constructor por Defecto : real(0.0), imag(0.0) {}
//---// devuelve la parte real del numero complejo double Complejo::parte_real() const
{
return real ; }
//---// devuelve la parte imaginaria del numero complejo double Complejo::parte_imag() const
{
return imag ; }
//---// asigna al numero complejo (actual) el resultado de // sumar los numeros complejos (a) y (b).
void Complejo::sumar(const Complejo& a, const Complejo& b) {
real = a.real + b.real ; imag = a.imag + b.imag ; }
//---// asigna al numero complejo (actual) el resultado de // restar los numeros complejos (a) y (b).
void Complejo::restar(const Complejo& a, const Complejo& b) {
real = a.real - b.real ; imag = a.imag - b.imag ; }
//---// asigna al numero complejo (actual) el resultado de // multiplicar los numeros complejos (a) y (b).
void Complejo::multiplicar(const Complejo& a, const Complejo& b) {
double p_real = (a.real * b.real) - (a.imag * b.imag) ; double p_imag = (a.real * b.imag) + (a.imag * b.real) ; real = p_real;
imag = p_imag; }
//---// asigna al numero complejo (actual) el resultado de // dividir los numeros complejos (a) y (b).
void Complejo::dividir(const Complejo& a, const Complejo& b) {
double divisor = sq(b.real) + sq(b.imag) ; if (iguales(0.0, divisor)) {
real = 0.0 ; imag = 0.0 ; } else {
double p_real = ((a.real * b.real) + (a.imag * b.imag)) / divisor ; double p_imag = ((a.imag * b.real) - (a.real * b.imag)) / divisor ; real = p_real;
imag = p_imag; }
}
bool Complejo::igual(const Complejo& b) const {
return iguales(real, b.real) && iguales(imag, b.imag) ; }
//---// muestra en pantalla el numero complejo (actual) void Complejo::escribir() const
{
cout << "{ " << real << ", " << imag << " }" ; }
//---// lee de teclado el valor del numero complejo (actual). // lee la parte real y la parte imaginaria del numero void Complejo::leer()
{
cin >> real >> imag ; }
//---}
Soluci´on: main.cpp #include <iostream>
#include "complejos.hpp" using namespace std ; using namespace umalcc ;
//---void leer(Complejo& c)
{
cout << "Introduzca un numero complejo { real img }: " ; c.leer() ;
}
//---void prueba_suma(const Complejo& c1, const Complejo& c2) {
Complejo c0 ; c0.sumar(c1, c2) ; c1.escribir() ; cout <<" + " ; c2.escribir() ; cout <<" = " ; c0.escribir() ; cout << endl ; Complejo aux ; aux.restar(c0, c2) ; if ( ! c1.igual(aux)) {
cout << "Error en operaciones de suma/resta"<< endl ; }
}
//---void prueba_resta(const Complejo& c1, const Complejo& c2) {
Complejo c0 ; c0.restar(c1, c2) ; c1.escribir() ; cout <<" - " ; c2.escribir() ; cout <<" = " ; c0.escribir() ; cout << endl ; Complejo aux ; aux.sumar(c0, c2) ; if ( ! c1.igual(aux)) {
cout << "Error en operaciones de suma/resta"<< endl ; }
}
//---void prueba_mult(const Complejo& c1, const Complejo& c2) {
Complejo c0 ;
c0.multiplicar(c1, c2) ; c1.escribir() ;
c0.escribir() ; cout << endl ; Complejo aux ; aux.dividir(c0, c2) ; if ( ! c1.igual(aux)) {
cout << "Error en operaciones de mult/div"<< endl ; }
}
//---void prueba_div(const Complejo& c1, const Complejo& c2) {
Complejo c0 ; c0.dividir(c1, c2) ; c1.escribir() ; cout <<" / " ; c2.escribir() ; cout <<" = " ; c0.escribir() ; cout << endl ; Complejo aux ;
aux.multiplicar(c0, c2) ; if ( ! c1.igual(aux)) {
cout << "Error en operaciones de mult/div"<< endl ; }
}
//---int main()
{
Complejo c1, c2 ; leer(c1) ; leer(c2) ;
//---prueba_suma(c1, c2) ;
prueba_resta(c1, c2) ; prueba_mult(c1, c2) ; prueba_div(c1, c2) ;
//---}
2. Dise˜
ne e implemente un TAD para n´
umeros racionales, as´ı como un programa para poder probar su
funcionamiento. Se deber´
an seguir las siguientes consideraciones:
Los n´
umeros racionales se representan mediante fracciones, donde tanto el numerador como
denom-inador son de tipo
int
).
Las fracciones se representar´
an en todo momento normalizadas (simplificadas):
•
Es recomendable implementar un m´
etodo privado de simplificaci´
on de la fracci´
on mediante el
c´
alculo del m´
aximo com´
un divisor (m.c.d.) del numerador y el denominador y su posterior divisi´
on
por dicho m.c.d.
•
Para simplificar la determinaci´
on del signo de la fracci´
on puede asumirse que el denominador de
la fracci´
on es siempre positivo (por lo que una fracci´
on de signo negativo tendr´
a un numerador
de signo negativo y un denominador de signo positivo).
Por defecto, un n´
umero racional debe asignarse a cero cuando se crea.
El cero se guardar´
a siempre en su forma can´
onica 0/1.
Debe evitarse en todo momento la asignaci´
on de cero a un denominador.
Un determinado m´
etodo permitir´
a comprobar si un determinado n´
umero racional se encuentra en
estado de error. Un denominador igual a cero (0) se considera un estado de error.
Debe proporcionar operaciones para crear, leer, asignar valores, escribir, sumar, restar, multiplicar y
dividir fracciones.
Debe poder ser posible crear n´
umeros racionales especificando su numerador y denominador, como
s´
olamente especificando su numerador (en este ´
ultimo caso, se considerar´
a un denominador igual a
1).
Soluci´on: racionales.hpp #ifndef _racionales_hpp_
#define _racionales_hpp_ namespace umalcc {
class Racional { public:
//---//-- Metodos Publicos --- //---//~Racional() {}
//Racional(const Racional& o);
//Racional& operator=(const Racional& o);
//---Racional() ;
// Construye el n´umero racional 0/1 //---Racional(int n) ;
// Construye el n´umero racional n/1 //---Racional(int n, int d) ;
// Construye el n´umero racional n/d //---bool fail() const;
// Devuelve true si el n´umero racional actual esta en estado erroneo
//---void sumar(const Racional& r1, const Racional& r2); // Asigna al n´umero racional actual el resultado de // sumar los n´umeros racionales (r1) y (r2)
//---void restar(const Racional& r1, const Racional& r2); // Asigna al n´umero racional actual el resultado de // restar los n´umeros racionales (r1) y (r2)
//---void multiplicar(const Racional& r1, const Racional& r2); // Asigna al n´umero racional actual el resultado de // multiplicar los n´umeros racionales (r1) y (r2)
//---void dividir(const Racional& r1, const Racional& r2); // Asigna al n´umero racional actual el resultado de // dividir los n´umeros racionales (r1) y (r2)
//---void escribir() const;
// Muestra en pantalla el valor del n´umero racional actual
//---void leer();
// Lee de teclado el valor del n´umero racional actual
//---bool igual(const Racional& r1) const;
// Devuelve true si el n´umero racional actual es igual a (r1)
//---bool menor(const Racional& r1) const;
// Devuelve true si el n´umero racional actual es menor que (r1) //---private:
//---//-- Metodos Privados --- //---void normalizar();
//---//-- Atributos Privados --- //---int num; // numerador
int denom; // denominador
//---};
} #endif
Soluci´on: racionales.cpp #include "racionales.hpp"
#include <iostream> using namespace std; using namespace umalcc ;
//---// Espacio de nombres anonimo. Es una parte privada de la // implementacion. No es accesible desde fuera del modulo
//---namespace {
//---//-- Subprogramas Auxiliares --- //---// valor absoluto de un numero entero inline int abs(int x)
{
if (x < 0) { x = -x; }
return x; }
//---// maximo comun divisor. algoritmo de euclides int mcd(int a, int b)
{
a = abs(a); b = abs(b); int res; if (a == 0) {
res = b; } else {
while (b != 0) { if (a > b) { a = a - b; } else {
b = b - a; }
} res = a; }
return res; }
//---// minimo comun multiplo
// inline int mcm(int a, int b) // {
// a = abs(a); // b = abs(b);
// return (a / mcd(a, b)) * b; // }
//---}
//---// Espacio de nombres umalcc.
// Aqui reside la implementacion de la parte publica del modulo
//---namespace umalcc {
Racional::Racional() : num(0), denom(1) {}
//---Racional::Racional(int n) : num(n), denom(1) {}
//---Racional::Racional(int n, int d) : num(n), denom(d) {
normalizar(); }
//---bool Racional::fail() const
{
return (denom == 0); }
//---// normalizar un numero racional void Racional::normalizar() {
if (denom == 0) {
// Error denominador cero num = 0;
denom = 0; } else if (num == 0) {
num = 0; denom = 1; } else {
// dividir numerador y denominador por MCD int max_com_div = mcd(num, denom);
num /= max_com_div; denom /= max_com_div;
// si denominador negativo, entonces cambiar signo if (denom < 0) {
num = -num; denom = -denom; }
} }
//---void Racional::sumar(const Racional& r1, const Racional& r2) {
//---// n1 n2 n1*d2 n2*d1 (n1*d2)+(n2*d1) // ---- + ---- == --- + --- == ---// d1 d2 d1*d2 d2*d1 d1*d2
//---num = ((r1.//---num * r2.denom) + (r2.//---num * r1.denom)); denom = r1.denom * r2.denom;
normalizar(); }
//---void Racional::restar(const Racional& r1, const Racional& r2) {
//---// n1 n2 n1*d2 n2*d1 (n1*d2)-(n2*d1) // ---- - ---- == --- - --- == ---// d1 d2 d1*d2 d2*d1 d1*d2
//---num = ((r1.//---num * r2.denom) - (r2.//---num * r1.denom)); denom = r1.denom * r2.denom;
normalizar(); }
//---void Racional::multiplicar(const Racional& r1, const Racional& r2) {
//---// n1 n2 n1*n2 // ---- * ---- == ---// d1 d2 d1*d2 //---num = r1.//---num * r2.//---num; denom = r1.denom * r2.denom; normalizar();
}
//---void Racional::dividir(const Racional& r1, const Racional& r2) {
//---// n1 n2 n1*d2 // ---- / ---- == ---// d1 d2 d1*n2 //---int p_num = r1.num * r2.denom; int p_denom = r1.denom * r2.num; num = p_num;
denom = p_denom; normalizar(); }
//---void Racional::escribir() const {
if (fail()) { cout << "Error"; } else {
cout << num << " / " << denom; }
}
//---void Racional::leer() {
cin >> num >> denom; normalizar(); }
//---bool Racional::igual(const Racional& r1) const {
// ambos numeros estan normalizados
return (num == r1.num && denom == r1.denom); }
//---bool Racional::menor(const Racional& r1) const {
//---// n1 n2 n1*d2 n2*d1 (n1*d2) < (n2*d1) // ---- < ---- ==> --- < --- ==> ---// d1 d2 d1*d2 d2*d1 d1*d2
//---return (num * r1.denom) < (r1.num * denom); }
//---}
Soluci´on: main.cpp #include <iostream>
#include <string> #include <cassert> #include "racionales.hpp" using namespace std; using namespace umalcc;
void escribir(const string& msj, const Racional& r) {
cout << msj; r.escribir(); cout << endl; }
int main() {
//---cout << "Introduzca numerador y denominador: "; Racional r1;
r1.leer();
escribir("R1: ", r1);
//---cout << "Introduzca numerador y denominador: "; Racional r2;
r2.leer();
escribir("R2: ", r2); //---Racional r3;
r3.sumar(r1, r2);
escribir("R3 (r1 + r2): ", r3); //---Racional r4;
r4.restar(r3, r2);
escribir("R4 (r3 - r2): ", r4); if ( ! r1.igual(r4)) {
cout << "Error en suma/resta"<<endl; }
//---Racional r5;
r5.multiplicar(r1, r2);
escribir("R5 (r1 * r2): ", r5); //---Racional r6;
r6.dividir(r5, r2);
escribir("R6 (r5 / r2): ", r6); if ( ! r1.igual(r6)) {
cout << "Error en multiplicacion/division"<<endl; }
3. TAD polinomio de grados positivos menores que 100 que defina los siguientes m´
etodos p´
ublicos:
Soluci´on: polinomios.hpp #ifndef _polinomios_hpp_
#define _polinomios_hpp_ #include <tr1/array> namespace umalcc {
//---const double ERROR_PRECISION = 1e-6; //---class Polinomio {
public:
//---//-- Metodos Publicos --- //---// Definidos automaticamente por el compilador
//---//~Polinomio();
//Polinomio(const Polinomio& p);
//Polinomio& operator=(const Polinomio& p);
//---Polinomio();
unsigned max_grado() const;
// Devuelve el mayor grado del polinomio actual // cuyo coeficiente es distinto de cero
void poner(unsigned e, double c);
// Asigna el coeficiente (c) al termino de grado (e) // del polinomio actual
double obtener(unsigned e) const;
// Devuelve el coeficiente correspondiente al // termino de grado (e) del polinomio actual double evaluar(double x) const;
// Devuelve el resultado de evaluar el polinomio actual // para un valor de (x) especificado como parametro void derivar(const Polinomio& a);
// Asigna al polinomio actual el resultado de // calcular la derivada del polinomio (a)
void sumar(const Polinomio& a, const Polinomio& b); // Asigna al polinomio actual el resultado de // sumar los polinomios (a) y (b)
void escribir() const;
// Muestra en pantalla el contenido del polinomio actual void leer();
// Lee de teclado el valor del polinomio actual
// Lee pares de coeficiente y grado hasta que el coeficiente sea cero
//---private:
//---//-- Ctes y Tipos Privados --- //---static const unsigned MAX = 100;
typedef std::tr1::array<double, MAX> Datos;
//---//-- Metodos Privados --- //---void inicializar();
//---//-- Atributos Privados --- //---unsigned mg; // maximo grado del polinomio
Datos coef; // coeficientes del polinomio (indice es el exp de la X)
//---}; } #endif
Soluci´on: polinomios.cpp #include "polinomios.hpp"
#include <iostream> #include <cassert> using namespace std; using namespace umalcc ;
//---// Espacio de nombres anonimo. Es una parte privada de la // implementacion. No es accesible desde fuera del modulo
//---namespace {
//---//-- Subprogramas Auxiliares --- //---// Valor absoluto de un numero inline double abs(double a) {
return (a >= 0) ? a : -a; }
//---// Dos numeros reales son iguales si la distancia que los // separa es lo suficientemente pequenya
inline bool iguales(double a, double b) { return abs(a-b) <= ERROR_PRECISION; }
//---double potencia(//---double base, unsigned exp) {
double res = 1;
for (unsigned i = 0; i < exp; ++i) { res *= base;
}
return res; }
}
//---// Espacio de nombres umalcc.
// Aqui reside la implementacion de la parte publica del modulo
//---namespace umalcc {
Polinomio::Polinomio() : mg(0), coef() {
inicializar(); }
//---unsigned Polinomio::max_grado() const {
return mg; }
//---void Polinomio::poner(unsigned e, double c) {
if (e < coef.size()) { coef[e] = c;
if ((e > mg) && !iguales(c, 0.0)) { mg = e;
} } }
//---double Polinomio::obtener(unsigned e) const {
double res; if (e < mg) {
res = coef[e]; } else {
res = 0.0; }
return res; }
//---double Polinomio::evaluar(//---double x) const {
double res = 0;
for (unsigned i = 0; i <= mg; ++i) { res += coef[i] * potencia(x, i); }
return res; }
{
assert(this != &a); inicializar();
for (unsigned i = 1; i <= a.mg; ++i) { coef[i-1] = a.coef[i]*i;
}
mg = a.mg-1; }
//---void Polinomio::sumar(const Polinomio& a, const Polinomio& b) {
assert((this != &a)&&(this != &b)); inicializar();
if (a.mg >= b.mg) { mg = a.mg; } else {
mg = b.mg; }
for (unsigned i = 0; i <= mg; ++i) { coef[i] = a.coef[i] + b.coef[i]; }
}
//---void Polinomio::escribir() const {
for (unsigned i = 0; i <= mg; ++i) { if (! iguales(coef[i], 0.0)) {
cout << (coef[i] > 0.0 ? " +" : " ") << coef[i] << " X^" << i ; }
} }
//---void Polinomio::leer()
{
inicializar(); double c;
cout << "Introduzca coeficiente [0 -> fin]: "; cin >> c;
while ( !cin.fail() && ! iguales(c, 0.0) ) { unsigned e;
cout << "Introduzca exponente: "; cin >> e;
if ( ! cin.fail() && (e < coef.size())) { coef[e] = c;
if (e > mg) { mg = e; }
}
cout << "Introduzca coeficiente [0 -> fin]: "; cin >> c;
} }
//---void Polinomio::inicializar() {
mg = 0;
for (unsigned i = 0; i < coef.size(); ++i) { coef[i] = 0.0;
} }
//---}
Soluci´on: main.cpp #include <iostream>
#include <string>
#include "polinomios.hpp" using namespace std; using namespace umalcc;
void escribir(const string& msj, const Polinomio& p) {
p.escribir(); cout << endl; }
int main() {
Polinomio p1, p2, p3; p1.leer();
escribir("P1: ", p1);
cout << "P1(2) = " << p1.evaluar(2.0) << endl; p2.derivar(p1);
escribir("P2: ", p2); p3.sumar(p1, p2); escribir("P3: ", p3); p1 = p3;
escribir("P1: ", p1); }
4. Un conjunto de n´
umeros enteros es una colecci´
on de elementos homog´
eneos (n´
umeros enteros) sin repetici´
on
y ninguna relaci´
on de orden entre ellos (no ordenados y sin repetici´
on). Defina un TAD Conjunto de
n´
umeros enteros que defina los siguientes m´
etodos p´
ublicos:
Soluci´on: conjuntos.hpp #ifndef _conjuntos_hpp_
#define _conjuntos_hpp_ #include <iostream> #include <tr1/array> namespace umalcc {
class Conjunto { public:
//---//-- Metodos Publicos --- //---// Generados automaticamente por el compilador
//---//~Conjunto();
//Conjunto(const Conjunto& c);
//Conjunto& operator=(const Conjunto& c); //---Conjunto();
// Constructor por Defecto: conjunto vacio void clear();
// Elimina todos los elementos del conjunto actual (queda vacio) bool es_vacio() const;
// Devuelve true si el conjunto actual esta vacio void incluir(int e);
// Incluye el elemento (e) en el conjunto actual void eliminar(int e);
// Elimina el elemento (e) del conjunto actual bool pertenece(int e) const;
// Devuelve true si el elemento (e) pertenece al conjunto actual bool es_subconjunto(const Conjunto& a) const;
// Devuelve true si el conjunto actual es subconjunto del conjunto (a) void union_conj(const Conjunto& a, const Conjunto& b);
// Asigna al conjunto actual el resultado de // la union de los conjuntos (a) y (b)
void interseccion(const Conjunto& a, const Conjunto& b); // Asigna al conjunto actual el resultado de
// la interseccion de los conjuntos (a) y (b)
void diferencia(const Conjunto& a, const Conjunto& b); // Asigna al conjunto actual el resultado de
// la diferencia de los conjuntos (a) y (b)
void diferencia_simetrica(const Conjunto& a, const Conjunto& b); // Asigna al conjunto actual el resultado de
// la diferencia simetrica de los conjuntos (a) y (b) void escribir() const;
// Muestra en pantalla el contenido del conjunto actual void leer();
// Lee de teclado el valor del conjunto actual, private:
--- //---static const unsigned MAX = 100;
typedef std::tr1::array<int, MAX> Datos;
//---//-- Metodos Privados --- //---void anyadir(int e) ;
void quitar(unsigned i) ; unsigned buscar(int e) const ;
//---//-- Atributos Privados --- //---unsigned sz; // numero de elementos del conjunto
Datos dat; // componentes del conjunto
//---};
} #endif
Soluci´on: conjuntos.cpp #include "conjuntos.hpp"
#include <iostream> #include <tr1/array> #include <cassert> using namespace std; namespace umalcc {
//---//-- Metodos Publicos --- //---Conjunto::Conjunto() : sz(0), dat() {}
//---void Conjunto::clear()
{
sz = 0; }
//---bool Conjunto::es_vacio() const
{
return (sz == 0); }
//---void Conjunto::incluir(int e)
{
if (! pertenece(e)) { anyadir(e); }
}
//---void Conjunto::eliminar(int e)
{
quitar(buscar(e)); }
//---bool Conjunto::pertenece(int e) const
{
return (buscar(e) < sz); }
//---bool Conjunto::es_subconjunto(const Conjunto& a) const
{
// es subconjunto si todos los elementos del conjunto actual // pertenecen tambien al conjunto especificado como parametro unsigned i = 0;
while ((i < sz) && a.pertenece(dat[i])) { ++i;
}
return (i == sz); }
//---void Conjunto::union_conj(const Conjunto& a, const Conjunto& b)
{
assert((this != &a)&&(this != &b)); clear();
anyadir(a.dat[i]); }
for (unsigned i = 0; i < b.sz; ++i) { incluir(b.dat[i]);
} }
//---void Conjunto::interseccion(const Conjunto& a, const Conjunto& b)
{
assert((this != &a)&&(this != &b)); clear();
for (unsigned i = 0; i < a.sz; ++i) { if (b.pertenece(a.dat[i])) {
anyadir(a.dat[i]); }
} }
//---void Conjunto::diferencia(const Conjunto& a, const Conjunto& b)
{
assert((this != &a)&&(this != &b)); clear();
for (unsigned i = 0; i < a.sz; ++i) { if (! b.pertenece(a.dat[i])) {
anyadir(a.dat[i]); }
} }
//---void Conjunto::diferencia_simetrica(const Conjunto& a, const Conjunto& b) {
Conjunto a_b, b_a; a_b.diferencia(a, b); b_a.diferencia(b, a); union_conj(a_b, b_a); }
//---void Conjunto::escribir() const
{
cout << "{ ";
for (unsigned i = 0; i < sz; ++i) { cout << dat[i] << " ";
}
cout << "}"; }
//---void Conjunto::leer()
{
clear(); int e; cin >> e ; while (e != 0) {
incluir(e); cin >> e ; }
}
//---//-- Metodos Privados --- //---void Conjunto::anyadir(int e) {
if (sz < dat.size()) { dat[sz] = e; ++sz; }
}
//---void Conjunto::quitar(unsigned i) {
// Elimina un elemento asignando el ultimo elemento a la // posicion especificada
if (i < sz) { if (i < sz-1) {
dat[i] = dat[sz-1]; }
} }
//---unsigned Conjunto::buscar(int e) const { unsigned i = 0;
while ((i < sz)&&(e != dat[i])) { ++i;
}
return i; }
//---}
Soluci´on: main.cpp #include <iostream>
#include <string> #include "conjuntos.hpp" using namespace std; using namespace umalcc;
void escribir(const string& msj, const Conjunto& c) {
cout << msj; c.escribir(); cout << endl; }
int main() {
Conjunto c1, c2, c3;
cout << "Introduzca elementos del conjunto: [0 -> fin]: "; c1.leer();
escribir("C1: ", c1);
cout << "Introduzca elementos del conjunto: [0 -> fin]: "; c2.leer();
escribir("C2: ", c2);
cout << "Es subconjunto: " << boolalpha << c1.es_subconjunto(c2) << endl; c3.union_conj(c1, c2);
escribir("Union: ", c3); c3.interseccion(c1, c2); escribir("Interseccion: ", c3); c3.diferencia(c1, c2);
escribir("Diferencia: ", c3); c3.diferencia_simetrica(c1, c2); escribir("Diferencia Simetrica: ", c3); }
5. TAD matriz matem´
atica de n´
umeros reales (de dimensiones menores de
N
×
N
) que defina los siguientes
m´
etodos p´
ublicos:
Soluci´on: matriz.hpp #ifndef _matriz_hpp_
#define _matriz_hpp_ #include <tr1/array> namespace umalcc {
//---const double ERROR_PRECISION = 1e-6; //---class Matriz {
public:
//---//-- Metodos Publicos --- //---// Definidos automaticamente por el compilador
//---//~Matriz();
//Matriz(const Matriz& m);
//Matriz& operator=(const Matriz& m); //---Matriz() ;
// Constructor por Defecto: matriz vacia
// Constructor especifico: crea matriz de (