• No results found

Practicas de Programacion 2 Ejercicios pdf

N/A
N/A
Protected

Academic year: 2020

Share "Practicas de Programacion 2 Ejercicios pdf"

Copied!
239
0
0

Loading.... (view fulltext now)

Full text

(1)

Programaci´

on II

Relaci´

on de Ejercicios

y Soluciones

Sonido e Imagen

UNIVERSIDAD DE M ´ALAGA

Dpto. 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

(2)

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); }

(3)

}

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;

(4)

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;

(5)

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

.

enero

char

(M/F).

Arte

char

(S/N).

Deporte

char

(S/N).

Libros

char

(S/N).

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; }

(6)

//---// 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]);

(7)

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; };

(8)

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 {

(9)

} }

// 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 {

(10)

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:

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);

(11)

}

// 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

>

[

<

,

<

=,

>

,

>

=, ==, ! =]

<

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; };

(12)

// 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;

(13)

}

//---//-- 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;

(14)

if (ok) {

procesar_fichero(nombre_ent, nombre_sal, c, ok); if (ok) {

cout << "Procesamiento correcto" << endl; } else {

cout << "Error al procesar el fichero" << endl; }

(15)

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 ; }

(16)

{

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)

{

(17)

//---// 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)) {

(18)

}

//---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

(19)

//---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

(20)

// 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);

}

(21)

//---// 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;

(22)

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 {

(23)

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) {

(24)

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 {

(25)

//---//-- 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 ; }

(26)

//---// 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; }

}

(27)

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() ;

(28)

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

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

olamente especificando su numerador (en este ´

ultimo caso, se considerar´

a un denominador igual a

1).

(29)

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 ;

(30)

//---// 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) {

(31)

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; }

}

(32)

//---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; }

(33)

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 ;

(34)

//---// 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; }

(35)

{

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) {

(36)

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

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:

(37)

--- //---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();

(38)

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]; }

(39)

} }

//---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

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

(40)

// Constructor especifico: crea matriz de (

References

Related documents

Considering the fact of increasing demand of home security and automation, an Android based control system is presented in this paper where the proposed system can maintain

The 2030 target is only possible to reach through fossil CO 2 emission reduction solutions that can work also on the stock of vehicles already on the market, because the addition

Collect the absorption spectrum of each oil sample using the single-beam background spectrum collected as described in 9.1  and using the operating parameters specified in

Terminal loss and • information leakage Security • vulnerabilities of wireless devices (sniffing and wiretapping) Mobile DDoS • AP no-security • setting Connection to •

Metatibia slightly shorter than metatarsus (0.9:1), with an oblique setiferous carina and small setiferous tooth on external side; upper apical spur articulated, slightly curved,

the copper and manganese levels range to a higher maximum value than observed for the San Cristobal samples, resulting in higher median values in the Huanqueros toenail

The researcher asked the management of the centre (seven members) some questions about quality awareness programs, the centre's role in adopting QMS-ISO 9000 standards implementation

In general, we expect integration of advanced analytical tools (R) with DBMSs for the purpose of performing complex analytics to provide benefits including the following: Provision