Programación II
Relación de Ejercicios
Sonido e Imagen
UNIVERSIDAD DE MÁLAGADpto. Lenguajes y CC. Computación E.T.S.I. Telecomunicación
Contenido
Tema 1: Almacenamiento en Memoria Secundaria. Ficheros 2
Tema 2: Tipos Abstractos de Datos 3
Tema 2.1: Programacion Modular. . . 3
Tema 2.2: Tipos Abstractos de Datos. . . 4
Tema 3: Gestión de Memoria Dinámica 8 Tema 3.1: Listas Enlazadas . . . 8
Tema 3.2: Abstracción en la Gestión de Memoria Dinámica . . . 10
Tema 4: Introducción a la Programación Orientada a Objetos 16 Tema 5: Colecciones 20 Prácticas de Laboratorio 21 Práctica 1: Almacenamiento Persistente de Datos . . . 21
Práctica 2: Tipos Abstractos de Datos (I) . . . 23
Práctica 3: Tipos Abstractos de Datos (II). . . 25
Práctica 4: Tipos Abstractos de Datos (III) . . . 27
Práctica 5: Gestión de Memoria Dinámica . . . 30
Práctica 6: Abstracción en la Gestión de Memoria Dinámica (I) . . . 31
Práctica 7: Abstracción en la Gestión de Memoria Dinámica (II) . . . 32
Práctica 8: Introducción a la Programación Orientada a Objetos . . . 34
Práctica 9: La Clase Vector de la Biblioteca Estándar . . . 38
Prácticas de Autoevaluación 40 Gestión de Factoría de Androides . . . 40
Gestión de Tareas Periódicas . . . 44
cc Esta obra se encuentra bajo una licenciaReconocimiento-NoComercial-CompartirIgual 4.0 Internacional(CC BY-NC-SA 4.0) de Creative Commons. Véasehttp://creativecommons.org/licenses/by-nc-sa/4.0/deed.es_ES
Tema 1: Almacenamiento en Memoria Secundaria. Ficheros
1. Escribir un programa que cuente el número de letras minúsculas, de letras mayúsculas y de dígitos de un fichero.
2. Escribir un programa con la opción de encriptar y de desencriptar un fichero de texto, dependiendo de la extensión del fichero de entrada. La encriptación (codificación) consiste en que dado un fichero de texto
de entrada (extensión txt) genere otro fichero de salida encriptado (extensión cod). Esta codificación
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ón de desencriptado consiste en leer un fichero codificado (extensióncod) y recuperar
la información original en un fichero de texto (extensióntxt).
3. Escribir un programa para procesar información sobre los clientes de una agencia matrimonial. El programa debe crear un fichero de texto (cuyo nombre se leerá por teclado) en el que se guarde la información de un número indeterminado de personas. La información que se guardará por cada persona será:
Nombre: Cadena de caracteres.
Edad int. Género char(M/F). Arte char(S/N). Deporte char(S/N). Libros char(S/N). Música char(S/N).
La información correspondiente a cada persona se leerá del teclado. El proceso finalizará cuando se teclee
un campo Nombreque esté vacío.
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á leído desde teclado) con toda la información correspondiente a los candidatos aceptados. Una persona del fichero de entrada se considerará aceptable como candidato si tiene diferente género y por lo menos tres aficiones comunes con respecto al aspirante introducido por pantalla. (El programa debe ser capaz de trabajar con cualquier número de personas en el fichero de entrada). 5. Codifique un programa que cree un fichero para contener los datos relativos a los artículos de un almacén.
Para cada artículo habrá de guardar la siguiente información:
Código del artículo Numérico
Nombre del artículo Cadena de caracteres
Existencias Numérico
Precio Numérico
Se deberá pedir datos de cada artículo por teclado hasta que se teclee 0 (cero) como código de artículo. 6. Escriba un programa que tome como entrada el fichero del ejercicio anterior y una condición sobre los
camposexistenciaso precio. La condición podrá ser:<campo>[<,<=,>,>=,==,! =]<número>
Este programa debe generar como salida un fichero que contenga todos aquellos artículos para los que se cumple la condición de entrada.
Tema 2: Tipos Abstractos de Datos
Tema 2.1: Programacion Modular
Diseñe e implemente los siguientes Módulos, dentro del espacio de nombres umalcc, así como programas de
utilización que permitan comprobar su funcionamiento.
1. Diseñe un módulo que proporcione soporte adecuado a la arímetica con números complejos. El módulo
deberá definir el tipoComplejo, así como los siguientes subprogramas:
void sumar ( Complejo& r, const Complejo& a, const Complejo& b) ;
// Devuelve un numero complejo ( r ) que c o n t i e n e e l r e s u l t a d o de // sumar l o s numeros complejos ( a ) y ( b ) .
void restar ( Complejo& r, const Complejo& a, const Complejo& b) ;
// Devuelve un numero complejo ( r ) que c o n t i e n e e l r e s u l t a d o de // r e s t a r l o s numeros complejos ( a ) y ( b ) .
void multiplicar ( Complejo& r, const Complejo& a, const Complejo& b) ;
// Devuelve un numero complejo ( r ) que c o n t i e n e e l r e s u l t a d o de // m u l t i p l i c a r l o s numeros complejos ( a ) y ( b ) .
void dividir ( Complejo& r, const Complejo& a, const Complejo& b) ;
// Devuelve un numero complejo ( r ) que c o n t i e n e e l r e s u l t a d o de // d i v i d i r l o s numeros complejos ( a ) y ( b ) .
bool iguales (const Complejo& a, const Complejo& b) ;
// Devuelve t r u e s i l o s numeros complejos ( a ) y ( b ) son i g u a l e s . void escribir (const Complejo& a) ;
// Muestra en p a n t a l l a e l numero complejo ( a ) void leer ( Complejo& a) ;
// Lee de t e c l a d o e l v a l o r d e l numero complejo ( a ) . // Lee l a p a r t e r e a l y l a p a r t e imaginaria d e l numero
2. Diseñe un módulo que proporcione soporte adecuado a la arímetica con números racionales. El módulo
deberá definir el tipoRacional, así como los subprogramas adecuados teniendo en cuenta las siguientes
consideraciones:
Los números racionales se representan mediante fracciones, donde tanto el numerador como
denomi-nador son de tipoint).
Las fracciones se representarán en todo momento normalizadas (simplificadas):
• Es recomendable implementar un subprograma privado de simplificación de la fracción mediante el cálculo del máximo común divisor (m.c.d.) del numerador y el denominador y su posterior división por dicho m.c.d.
Para calcular el máximo común divisor de dos numeros enteros positivosnym, el algoritmo de
Euclides funciona como se indica a continuación:
a) Sin < m, entonces se intercambian los valores denym(para asegurarnos quensiempre sea mayor o igual quem).
b) Si el valor demes distinto de0, entonces sear el resto de la división entera entren ym; después modificamos los valores denymde la siguiente forma:ntoma ahora el valor demymtoma ahora el valor der (el resto de la división entera entren y mcalculado anteriormente), y se repite este proceso especificado hasta que el valor demsea igual a0.
c) Finalmente, cuando el proceso iterativo acaba, el valor denes el máximo común divisor de ambos números.
• Para simplificar la determinación del signo de la fracción puede asumirse que el denominador de la fracción es siempre positivo (por lo que una fracción de signo negativo tendrá un numerador de signo negativo y un denominador de signo positivo).
El número cero se guardará siempre en su forma canónica 0/1.
Debe evitarse en todo momento la asignación de cero a un denominador.
Debe proporcionar subprogramas para leer, escribir, sumar, restar, multiplicar y dividir fracciones. Pueden también suministrarse métodos para comparación de números racionales (iguales, menor, etc).
void sumar ( Racional& r, const Racional& r1 , const Racional& r2 );
// Asigna a l numero r a c i o n a l ( r ) e l r e s u l t a d o de // sumar l o s numeros r a c i o n a l e s ( r1 ) y ( r2 )
// Asigna a l numero r a c i o n a l ( r ) e l r e s u l t a d o de // r e s t a r l o s numeros r a c i o n a l e s ( r1 ) y ( r2 )
void multiplicar ( Racional& r, const Racional& r1 , const Racional& r2 );
// Asigna a l numero r a c i o n a l ( r ) e l r e s u l t a d o de // m u l t i p l i c a r l o s numeros r a c i o n a l e s ( r1 ) y ( r2 )
void dividir ( Racional& r, const Racional& r1 , const Racional& r2 );
// Asigna a l numero r a c i o n a l ( r ) e l r e s u l t a d o de // d i v i d i r l o s numeros r a c i o n a l e s ( r1 ) y ( r2 ) void escribir (const Racional& r);
// Muestra en p a n t a l l a e l v a l o r d e l numero r a c i o n a l ( r ) void leer ( Racional& r);
// Lee de t e c l a d o e l v a l o r d e l numero r a c i o n a l ( r ) bool igual (const Racional& r1 , const Racional& r2 );
// Devuelve t r u e s i e l numero r a c i o n a l ( r1 ) es i g u a l a ( r2 ) bool menor (const Racional& r1 , const Racional& r2 );
// Devuelve t r u e s i e l numero r a c i o n a l ( r1 ) es menor que ( r2 )
3. Diseñe un módulo que proporcione soporte adecuado a la manipulación de polinomios de grados positivos
menores que 100. El módulo deberá definir el tipo Polinomio, así como las siguientes operaciones:
double evaluar (const Polinomio& a, double x);
// Devuelve e l r e s u l t a d o de e v a l u a r e l polinomio ( a ) // para un v a l o r de ( x ) e s p e c i f i c a d o como parametro void derivar ( Polinomio& r, const Polinomio& a);
// PRECOND: (&r != &a )
// Devuelve un polinomio ( r ) que c on t i e n e e l r e s u l t a d o de // c a l c u l a r l a derivada d e l polinomio ( a )
void sumar ( Polinomio& r, const Polinomio& a, const Polinomio& b);
// PRECOND: ((& r != &a)&&(&r != &b ) )
// Devuelve un polinomio ( r ) que c o n t i e n e e l r e s u l t a d o de // sumar l o s polinomios ( a ) y ( b )
void escribir (const Polinomio& a) ;
// Muestra en p a n t a l l a e l contenido d e l polinomio ( a ) void leer ( Polinomio& a) ;
// Lee de t e c l a d o e l v a l o r d e l polinomio ( a )
// Lee pares de c o e f i c i e n t e y grado hasta que e l c o e f i c i e n t e sea cero
Tema 2.2: Tipos Abstractos de Datos
Diseñe e implemente los siguientes TADs, dentro del espacio de nombres umalcc, así como programas de
utilización que permitan comprobar su funcionamiento.
1. TAD número complejo que defina los siguientes métodos públicos: class Complejo {
public:
Complejo () ;
// Constructor por Defecto
Complejo (double parte_real , double parte_imag ) ;
// Constructor e s p e c i f i c o double parte_real () const ;
// Devuelve l a p a r t e r e a l d e l numero complejo double parte_imag () const ;
// Devuelve l a p a r t e imaginaria d e l numero complejo void sumar (const Complejo& a, const Complejo& b) ;
// Asigna a l numero complejo ( a c t u a l ) e l r e s u l t a d o de // sumar l o s numeros complejos ( a ) y ( b ) .
void restar (const Complejo& a, const Complejo& b) ;
// Asigna a l numero complejo ( a c t u a l ) e l r e s u l t a d o de // r e s t a r l o s numeros complejos ( a ) y ( b ) .
void multiplicar (const Complejo& a, const Complejo& b) ;
// Asigna a l numero complejo ( a c t u a l ) e l r e s u l t a d o de // m u l t i p l i c a r l o s numeros complejos ( a ) y ( b ) . void dividir (const Complejo& a, const Complejo& b) ;
// Asigna a l numero complejo ( a c t u a l ) e l r e s u l t a d o de // d i v i d i r l o s numeros complejos ( a ) y ( b ) .
bool igual (const Complejo& b) const ;
// Devuelve t r u e s i e l numero complejo ( a c t u a l ) es // i g u a l a l numero complejo ( b )
void escribir () const ;
void leer () ;
// Lee de t e c l a d o e l v a l o r d e l numero complejo ( a c t u a l ) . // Lee l a p a r t e r e a l y l a p a r t e imaginaria d e l numero
} ;
2. TAD polinomio de grados positivos menores que 100 que defina los siguientes métodos públicos: class Polinomio {
public:
˜ Polinomio ();
// Destructor
Polinomio ();
// Constructor por Defecto
Polinomio (const Polinomio& p);
// Constructor de copia
Polinomio& operator=(const Polinomio& p);
// Operador de Asignacion int max_grado () const;
// Devuelve e l mayor grado d e l polinomio a c t u a l // cuyo c o e f i c i e n t e es d i s t i n t o de cero
void poner (int e, double c);
// Asigna e l c o e f i c i e n t e ( c ) a l termino de grado ( e ) // d e l polinomio a c t u a l
double obtener (int e) const;
// Devuelve e l c o e f i c i e n t e c o r r e s p o n d i e n t e a l // termino de grado ( e ) d e l polinomio a c t u a l double evaluar (double x) const;
// Devuelve e l r e s u l t a d o de e v a l u a r e l polinomio a c t u a l // para un v a l o r de ( x ) e s p e c i f i c a d o como parametro void derivar (const Polinomio& a);
// PRECOND: ( t h i s != &a )
// Asigna a l polinomio a c t u a l e l r e s u l t a d o de // c a l c u l a r l a derivada d e l polinomio ( a ) void sumar (const Polinomio& a, const Polinomio& b);
// PRECOND: ( ( t h i s != &a)&&( t h i s != &b ) ) // Asigna a l polinomio a c t u a l e l r e s u l t a d o de // sumar l o s polinomios ( a ) y ( b )
void escribir () const;
// Muestra en p a n t a l l a e l contenido d e l polinomio a c t u a l void leer ();
// Lee de t e c l a d o e l v a l o r d e l polinomio a c t u a l
// Lee pares de c o e f i c i e n t e y grado hasta que e l c o e f i c i e n t e sea cero
};
3. Un conjunto de números enteros es una colección de elementos homogéneos (números enteros) sin repetición y ninguna relación de orden entre ellos (no ordenados y sin repetición). Defina un TAD Conjunto de números enteros que defina los siguientes métodos públicos:
class Conjunto {
public:
˜ Conjunto ();
// Destructor
Conjunto ();
// Constructor por Defecto : conjunto vacio
Conjunto (const Conjunto& c);
// Constructor de copia
Conjunto& operator=(const Conjunto& c);
// Operador de Asignacion void clear ();
// Elimina todos l o s elementos d e l conjunto a c t u a l ( queda vacio ) bool es_vacio () const;
// Devuelve t r u e s i e l conjunto a c t u a l e s t a vacio void incluir (int e);
// I n c l u y e e l elemento ( e ) en e l conjunto a c t u a l ( s i n r e p e t i c i o n ) void eliminar (int e);
// Elimina e l elemento ( e ) d e l conjunto a c t u a l bool pertenece (int e) const;
// Devuelve t r u e s i e l elemento ( e ) p e rt e n ec e a l conjunto a c t u a l bool es_subconjunto (const Conjunto& a) const;
// Devuelve t r u e s i e l conjunto a c t u a l es subconjunto d e l conjunto ( a ) void union_conj (const Conjunto& a, const Conjunto& b);
// Asigna a l conjunto a c t u a l e l r e s u l t a d o de // l a union de l o s conjuntos ( a ) y ( b )
void interseccion (const Conjunto& a, const Conjunto& b);
// PRECOND: ( ( t h i s != &a)&&( t h i s != &b ) ) // Asigna a l conjunto a c t u a l e l r e s u l t a d o de // l a i n t e r s e c c i o n de l o s conjuntos ( a ) y ( b ) void diferencia (const Conjunto& a, const Conjunto& b);
// PRECOND: ( ( t h i s != &a)&&( t h i s != &b ) ) // Asigna a l conjunto a c t u a l e l r e s u l t a d o de // l a d i f e r e n c i a de l o s conjuntos ( a ) y ( b )
void diferencia_simetrica (const Conjunto& a, const Conjunto& b);
// Asigna a l conjunto a c t u a l e l r e s u l t a d o de
// l a d i f e r e n c i a s i m e t r i c a de l o s conjuntos ( a ) y ( b ) void escribir () const;
// Muestra en p a n t a l l a e l contenido d e l conjunto a c t u a l void leer ();
// Lee de t e c l a d o e l v a l o r d e l conjunto actual ,
};
4. TAD matriz matemática de números reales (de dimensiones menores deN×N) que defina los siguientes
métodos públicos: class Matriz { public: ˜ Matriz (); // Destructor Matriz ();
// Constructor por Defecto : matriz vacia
Matriz (int nfils , int ncols );
// Constructor e s p e c i f i c o : crea matriz de ( n f i l s ) x ( n c o l s ) con v a l o r e s 0
Matriz (const Matriz& m);
// Constructor de copia
Matriz& operator=(const Matriz& m);
// Operador de Asignacion void clear (int nfils , int ncols );
// Elimina todos l o s elementos de l a matriz actual , y asigna
// a l a matriz a c t u a l una matriz de ( n f i l s ) x ( n c o l s ) con v a l o r e s 0 int nfils () const;
// Devuelve e l numero de f i l a s de l a matriz a c t u a l int ncols () const;
// Devuelve e l numero de columnas de l a matriz a c t u a l void poner (int f, int c, double val );
// PRECOND: (0 <= f && f < n f i l s ( ) && 0 <= c && c < n c o l s ( ) ) // Asigna e l v a l o r ( v a l ) a l elemento de l a f i l a ( f )
// y columna ( c ) de l a matriz a c t u a l double obtener (int f, int c) const;
// PRECOND: ( f < n f i l s ( ) && c < n c o l s ( ) )
// Devuelve e l v a l o r d e l elemento de l a f i l a ( f ) // y columna ( c ) de l a matriz a c t u a l
void sumar (const Matriz& a, const Matriz& b);
// PRECOND: ( ( t h i s != &a)&&( t h i s != &b ) ) // Asigna a l a matriz a c t u a l e l r e s u l t a d o de // sumar l a s matrices ( a ) y ( b )
void restar (const Matriz& a, const Matriz& b);
// PRECOND: ( ( t h i s != &a)&&( t h i s != &b ) ) // Asigna a l a matriz a c t u a l e l r e s u l t a d o de // r e s t a r l a s matrices ( a ) y ( b )
void multiplicar (const Matriz& a, const Matriz& b);
// PRECOND: ( ( t h i s != &a)&&( t h i s != &b ) ) // Asigna a l a matriz a c t u a l e l r e s u l t a d o de // m u l t i p l i c a r l a s matrices ( a ) y ( b )
void escribir () const;
// Muestra en p a n t a l l a e l contenido de l a matriz a c t u a l void leer ();
// Lee de t e c l a d o e l v a l o r de l a matriz actual , // Lee n f i l s , n c o l s y l o s v a l o r e s de l o s elementos
};
5. Un TAD Lista de números enteros es una secuencia de elementos homogéneos (números enteros), donde cada elemento ocupa una determinada posición dentro de la secuencia, de tal forma que se puede acceder a cada elemento por la posición donde se encuentra. Así mismo, también es posible insertar y eliminar
elementos de la secuencia en la posición indicada, manteniendo el mismo orden posicional de los elementos en la secuencia. Diseñe e implemente el TAD que proporcione los siguientes métodos públicos:
class ListaInt {
public:
˜ ListaInt () ;
// Destructor
ListaInt () ;
// Constructor por Defecto
ListaInt (const ListaInt& o) ;
// Constructor de copia
ListaInt& operator = (const ListaInt& o) ;
// Operador de Asignacion bool llena () const ;
// Devuelve t r u e s i e l numero de elementos almacenados // alcanza l a capacidad maxima de almacenamiento int size () const ;
// Devuelve e l numero de elementos almacenados void clear () ;
// Elimina todos l o s elementos de l a l i s t a a c t u a l ( queda vacia ) void insertar (int pos , int dato ) ;
// PRECOND: ( ! l l e n a ( ) && 0 <= pos && pos <= s i z e ( ) ) // I n s e r t a ( dato ) en l a l i s t a a c t u a l en l a p o s i c i o n ( pos ) void eliminar (int pos ) ;
// PRECOND: (0 <= pos && pos < s i z e ( ) )
// Elimina de l a l i s t a a c t u a l e l elemento que ocupa l a p o s i c i o n ( pos ) int acceder (int pos ) const ;
// PRECOND: (0 <= pos && pos < s i z e ( ) )
// Devuelve e l elemento de l a l i s t a a c t u a l que ocupa l a p o s i c i o n ( pos ) void modificar (int pos , int dato );
// PRECOND: (0 <= pos && pos < s i z e ( ) )
// Asigna ( dato ) a l elemento de l a l i s t a a c t u a l que ocupa l a p o s i c i o n ( pos )
Tema 3: Gestión de Memoria Dinámica
Tema 3.1: Listas Enlazadas
1. Diseñe un módulo(programación modular)que proporcione soporte adecuado a la manipulación de listas
enlazadas en memoria dinámica (véase siguiente figura). El módulo deberá definir el tipoPNodocomo un
puntero a un registro en memoria dinámica de tipo Nodo que contiene un enlace al siguiente nodo, así
como un dato de tipoint. Además, el módulo deberá definir los siguientes subprogramas. Diseñe también
un módulo principal que permita comprobar la corrección del módulo lista implementado. lista: ◦−−→ ◦−−−−→ 0 −−−−→ ◦ 1 2
void inicializa ( PNodo& lista ) ;
// I n i c i a l i z a ( l i s t a ) a una l i s t a vacia void destruir ( PNodo& lista ) ;
// Destruye todos l o s elementos de l a l i s t a , l i b e r a n d o // todos l o s nodos de memoria dinamica . ( l i s t a ) queda vacia void escribir ( PNodo lista ) ;
// Muestra en p a n t a l l a e l contenido de ( l i s t a )
PNodo buscar ( PNodo lista , int dt) ;
// Devuelve un puntero a l nodo que co n t i en e e l elemento // i g u a l a ( dt ) . Si no se encuentra , entonces d e v u e l v e NULL void insertar_principio ( PNodo& lista , int dt) ;
// I n s e r t a un elemento a l p r i n c i p i o de ( l i s t a ) void insertar_final ( PNodo& lista , int dt) ;
// I n s e r t a un elemento a l f i n a l de ( l i s t a ) void insertar_ord ( PNodo& lista , int dt) ;
// I n s e r t a un elemento de forma ordenada en ( l i s t a ) , que debe e s t a r ordenada void eliminar_primero ( PNodo& lista ) ;
// Elimina e l primer elemento de ( l i s t a ) , s i e x i s t e void eliminar_ultimo ( PNodo& lista ) ;
// Elimina e l ultimo elemento de ( l i s t a ) , s i e x i s t e void eliminar_elem ( PNodo& lista , int dt) ;
// Elimina de ( l i s t a ) e l primer elemento i g u a l a ( dt ) , s i e x i s t e
PNodo situar ( PNodo lista , int pos ) ;
// Devuelve un puntero a l nodo que se encuentra en l a p o s i c i o n // indicada por ( pos ) . La p o s i c i o n cero (0) i n d i c a e l primer nodo . // Si e l nodo no e x i s t e , entonces d e v u e l v e NULL
void insertar ( PNodo& lista , int pos , int dt) ;
// I n s e r t a en ( l i s t a ) un elemento en l a p o s i c i o n indicada por ( pos ) void eliminar ( PNodo& lista , int pos ) ;
// Elimina de ( l i s t a ) e l elemento de l a p o s i c i o n indicada por ( pos ) , s i e x i s t e
PNodo duplicar ( PNodo lista ) ;
// Devuelve un puntero a una nueva l i s t a r e s u l t a d o de d u p l i c a r en // memoria dinamica l a l i s t a r e c i b i d a como parametro
PNodo leer () ;
// Devuelve una l i s t a con l o s numeros l e i d o s de t e c l a d o ( en e l mismo // orden que son i n t r o d u c i d o s ) hasta que l e a e l numero 0 ( que no es // i n t r o d u c i d o )
void eliminar_mayor ( PNodo& lista ) ;
// Elimina e l mayor elemento de ( l i s t a ) , s i e x i s t e void purgar ( PNodo& lista , int dt) ;
// Elimina de ( l i s t a ) todos l o s elementos que sean i g u a l e s a ( dt ) , s i e x i s t e n 2. Un conjunto de números enteros es una colección de elementos homogéneos (números enteros) sin repetición
y ninguna relación de orden entre ellos (no ordenados y sin repetición).
Un conjunto de elementos se puede representar mediante una lista enlazada, donde cada nodo contiene
un elemento del conjunto. Por ejemplo el conjunto con los elementos {1,2,3}puede ser representado por
la siguiente lista enlazada:
lista: ◦−−→ ◦−−−−→ 1 −−−−→ ◦ 2 3
Diseñe un módulo(programación modular) que proporcione soporte adecuado a la manipulación de
con-juntos de números enteros implementados mediante listas enlazadas en memoria dinámica (véase figura
anterior). El módulo deberá definir el tipoConjuntocomo un registro con un campo de tipoPNodo, que se
define como un tipo puntero a un registro en memoria dinámica de tipoNodoque contiene un enlace al
si-guiente nodo, así como un dato de tipoint. Además, el módulo deberá definir los siguientes subprogramas.
Diseñe también un módulo principal que permita comprobar la corrección del módulo implementado. void inicializar ( Conjunto& c);
// I n i c i a l i z a ( c ) a un conjunto vacio void destruir ( Conjunto& c);
// Destruye todos l o s elementos d e l conjunto , l i b e r a n d o // todos l o s nodos de memoria dinamica . ( c ) queda vacio bool es_vacio (const Conjunto& c) ;
// Devuelve t r u e s i e l conjunto ( c ) e s t a vacio void incluir ( Conjunto& c, int e);
// I n c l u y e e l elemento ( e ) en e l conjunto ( c ) ( s i n r e p e t i c i o n ) void eliminar ( Conjunto& c, int e);
// Elimina e l elemento ( e ) d e l conjunto ( c ) bool pertenece (const Conjunto& c, int e) ;
// Devuelve t r u e s i e l elemento ( e ) p e rt e n ec e a l conjunto ( c ) void escribir (const Conjunto& c) ;
// Muestra en p a n t a l l a e l contenido d e l conjunto ( c ) void leer ( Conjunto& c);
// Lee de t e c l a d o e l v a l o r d e l conjunto ( c )
bool es_subconjunto (const Conjunto& a, const Conjunto& b) ;
// Devuelve t r u e s i e l conjunto ( a ) es subconjunto d e l conjunto ( b ) void union_conj ( Conjunto& c, const Conjunto& a, const Conjunto& b);
// Asigna a l conjunto ( c ) e l r e s u l t a d o de
// l a union de l o s conjuntos ( a ) y ( b ) ( d u p l i c a l o s nodos )
void interseccion ( Conjunto& c, const Conjunto& a, const Conjunto& b);
// Asigna a l conjunto ( c ) e l r e s u l t a d o de
// l a i n t e r s e c c i o n de l o s conjuntos ( a ) y ( b ) ( d u p l i c a l o s nodos ) void diferencia ( Conjunto& c, const Conjunto& a, const Conjunto& b);
// Asigna a l conjunto ( c ) e l r e s u l t a d o de
// l a d i f e r e n c i a de l o s conjuntos ( a ) y ( b ) ( d u p l i c a l o s nodos )
void diferencia_simetrica ( Conjunto& c, const Conjunto& a, const Conjunto& b);
// Asigna a l conjunto ( c ) e l r e s u l t a d o de
// l a d i f e r e n c i a s i m e t r i c a de l o s conjuntos ( a ) y ( b ) ( d u p l i c a l o s nodos ) void copiar ( Conjunto& d, const Conjunto& o) ;
// Copia ( d u p l i c a ) e l conjunto ( o ) en e l conjunto ( d )
Nota: aunque el orden en el que se encuentran los elementos en el conjunto no es importante, y por lo tanto, la opción más simple para incluir elementos en él podría ser “insertar siempre los elementos por el principio”, con objeto de prácticar los conceptos de listas enlazadas, en esta práctica, los elementos del conjunto serán insertados (sin repetición) ordenados en la lista enlazada donde se encuentran almacenados.
3. Diseñe un módulo(programación modular)que proporcione soporte adecuado a la manipulación de listas
doblemente enlazadas en memoria dinámica (véase siguiente figura). El módulo deberá definir el tipo PNodocomo un puntero a un registro en memoria dinámica de tipoNodoque contiene un enlace al siguiente
nodo, un enlace al nodo anterior, así como un dato de tipo int. Además, el módulo deberá definir los
siguientes subprogramas. Diseñe también un módulo principal que permita comprobar la corrección del módulo lista implementado.
lista: ◦−−→ −−−−−→ ◦ 0 −−−−−→ ◦ ←−−−−−◦ 1 ←−−−−−◦ 2
void inicializa ( PNodo& lista ) ;
// I n i c i a l i z a ( l i s t a ) a una l i s t a vacia void destruir ( PNodo& lista ) ;
// Destruye todos l o s elementos de l a l i s t a , l i b e r a n d o // todos l o s nodos de memoria dinamica . ( l i s t a ) queda vacia void escribir ( PNodo lista ) ;
// Muestra en p a n t a l l a e l contenido de ( l i s t a )
PNodo buscar ( PNodo lista , int dt) ;
// Devuelve un puntero a l nodo que co n t i en e e l elemento // i g u a l a ( dt ) . Si no se encuentra , entonces d e v u e l v e NULL
void insertar_principio ( PNodo& lista , int dt) ;
// I n s e r t a un elemento a l p r i n c i p i o de ( l i s t a ) void insertar_final ( PNodo& lista , int dt) ;
// I n s e r t a un elemento a l f i n a l de ( l i s t a ) void insertar_ord ( PNodo& lista , int dt) ;
// I n s e r t a un elemento de forma ordenada en ( l i s t a ) , que debe e s t a r ordenada void eliminar_primero ( PNodo& lista ) ;
// Elimina e l primer elemento de ( l i s t a ) , s i e x i s t e void eliminar_ultimo ( PNodo& lista ) ;
// Elimina e l ultimo elemento de ( l i s t a ) , s i e x i s t e void eliminar_elem ( PNodo& lista , int dt) ;
// Elimina de ( l i s t a ) e l primer elemento i g u a l a ( dt ) , s i e x i s t e
PNodo situar ( PNodo lista , int pos ) ;
// Devuelve un puntero a l nodo que se encuentra en l a p o s i c i o n // indicada por ( pos ) . La p o s i c i o n cero (0) i n d i c a e l primer nodo . // Si e l nodo no e x i s t e , entonces d e v u e l v e NULL
void insertar ( PNodo& lista , int pos , int dt) ;
// I n s e r t a en ( l i s t a ) un elemento en l a p o s i c i o n indicada por ( pos ) void eliminar ( PNodo& lista , int pos ) ;
// Elimina de ( l i s t a ) e l elemento de l a p o s i c i o n indicada por ( pos ) , s i e x i s t e
PNodo duplicar ( PNodo lista ) ;
// Devuelve un puntero a una nueva l i s t a r e s u l t a d o de d u p l i c a r en // memoria dinamica l a l i s t a r e c i b i d a como parametro
PNodo leer () ;
// Devuelve una l i s t a con l o s numeros l e i d o s de t e c l a d o ( en e l mismo // orden que son i n t r o d u c i d o s ) hasta que l e a e l numero 0 ( que no es // i n t r o d u c i d o )
void eliminar_mayor ( PNodo& lista ) ;
// Elimina e l mayor elemento de ( l i s t a ) , s i e x i s t e void purgar ( PNodo& lista , int dt) ;
// Elimina de ( l i s t a ) todos l o s elementos que sean i g u a l e s a ( dt ) , s i e x i s t e n
Tema 3.2: Abstracción en la Gestión de Memoria Dinámica
1. Un polinomio enxde grado arbitrario se puede representar mediante una lista enlazada, donde cada nodo
contiene el coeficiente y el exponente de un término del polinomio, y donde los coeficientes con valor cero
(0) no serán almacenados. Por ejemplo el polinomio 25x−14x5 puede ser representado por la siguiente
lista enlazada: lista: ◦−−→ −−−−→ ◦ 25 1 -14 5
Diseñe e implemente el TAD polinomio que defina los siguientes métodos públicos, así como un programa para comprobar su funcionamiento:
class Polinomio {
public:
˜ Polinomio ();
// Destructor
Polinomio ();
// Constructor por Defecto
Polinomio (const Polinomio& p);
// Constructor de copia
Polinomio& operator=(const Polinomio& p);
// Operador de Asignacion int max_grado () const;
// Devuelve e l mayor grado d e l polinomio a c t u a l // cuyo c o e f i c i e n t e es d i s t i n t o de cero
void poner (int e, double c);
// Asigna e l c o e f i c i e n t e ( c ) a l termino de grado ( e ) // d e l polinomio a c t u a l
double obtener (int e) const;
// Devuelve e l c o e f i c i e n t e c o r r e s p o n d i e n t e a l // termino de grado ( e ) d e l polinomio a c t u a l double evaluar (double x) const;
// Devuelve e l r e s u l t a d o de e v a l u a r e l polinomio a c t u a l // para un v a l o r de ( x ) e s p e c i f i c a d o como parametro void derivar (const Polinomio& a);
// Asigna a l polinomio a c t u a l e l r e s u l t a d o de // c a l c u l a r l a derivada d e l polinomio ( a ) void sumar (const Polinomio& a, const Polinomio& b);
// Asigna a l polinomio a c t u a l e l r e s u l t a d o de // sumar l o s polinomios ( a ) y ( b )
void escribir () const;
// Muestra en p a n t a l l a e l contenido d e l polinomio a c t u a l void leer ();
// Lee de t e c l a d o e l v a l o r d e l polinomio a c t u a l
// Lee pares de c o e f i c i e n t e y grado hasta que e l c o e f i c i e n t e sea cero
};
2. Un conjunto de números enteros es una colección de elementos homogéneos (números enteros) sin repetición y ninguna relación de orden entre ellos (no ordenados y sin repetición).
Un conjunto de elementos se puede representar mediante una lista enlazada, donde cada nodo contiene
un elemento del conjunto. Por ejemplo el conjunto con los elementos {1,2,3}puede ser representado por
la siguiente lista enlazada:
lista: ◦−−→ ◦−−−−→ 1 −−−−→ ◦ 2 3
Diseñe e implemente el siguiente TAD conjunto de números enteros que defina los siguientes métodos públicos, así como un programa para comprobar su funcionamiento:
class Conjunto {
public:
˜ Conjunto ();
// Destructor
Conjunto ();
// Constructor por Defecto : conjunto vacio
Conjunto (const Conjunto& c);
// Constructor de copia
Conjunto& operator=(const Conjunto& c);
// Operador de Asignacion void clear ();
// Elimina todos l o s elementos d e l conjunto a c t u a l ( queda vacio ) bool es_vacio () const;
// Devuelve t r u e s i e l conjunto a c t u a l e s t a vacio void incluir (int e);
// I n c l u y e e l elemento ( e ) en e l conjunto a c t u a l ( s i n r e p e t i c i o n ) void eliminar (int e);
// Elimina e l elemento ( e ) d e l conjunto a c t u a l bool pertenece (int e) const;
// Devuelve t r u e s i e l elemento ( e ) p e rt e n ec e a l conjunto a c t u a l bool es_subconjunto (const Conjunto& a) const;
// Devuelve t r u e s i e l conjunto a c t u a l es subconjunto d e l conjunto ( a ) void union_conj (const Conjunto& a, const Conjunto& b);
// Asigna a l conjunto a c t u a l e l r e s u l t a d o de // l a union de l o s conjuntos ( a ) y ( b )
void interseccion (const Conjunto& a, const Conjunto& b);
// Asigna a l conjunto a c t u a l e l r e s u l t a d o de // l a i n t e r s e c c i o n de l o s conjuntos ( a ) y ( b ) void diferencia (const Conjunto& a, const Conjunto& b);
// Asigna a l conjunto a c t u a l e l r e s u l t a d o de // l a d i f e r e n c i a de l o s conjuntos ( a ) y ( b )
void diferencia_simetrica (const Conjunto& a, const Conjunto& b);
// Asigna a l conjunto a c t u a l e l r e s u l t a d o de
// l a d i f e r e n c i a s i m e t r i c a de l o s conjuntos ( a ) y ( b ) void escribir () const;
// Muestra en p a n t a l l a e l contenido d e l conjunto a c t u a l void leer ();
// Lee de t e c l a d o e l v a l o r d e l conjunto actual ,
};
3. Hay muchas aplicaciones en las que se deben almacenar en la memoria matrices de grandes dimensiones. Si la mayoría de los elementos de la matriz son ceros, ésta, en lugar de almacenarse en un array bidimensional, se puede representar más eficientemente utilizando listas enlazadas donde los elementos nulos y filas nulas
Así, defina la claseMatrizDispersaen el espacio de nombresumalcc_auxque represente dicha abstracción y proporcione las siguientes operaciones:
class MatrizDispersa {
public:
˜ MatrizDispersa ();
// Destructor
MatrizDispersa ();
// Constructor por Defecto : matriz vacia
MatrizDispersa (int nfils , int ncols );
// Constructor e s p e c i f i c o : crea matriz de ( n f i l s ) x ( n c o l s ) con v a l o r e s 0
MatrizDispersa (const MatrizDispersa& m);
// Constructor de copia
MatrizDispersa& operator=(const MatrizDispersa& m);
// Operador de Asignacion void clear (int nfils , int ncols );
// Elimina todos l o s elementos de l a matriz actual , y asigna
// a l a matriz a c t u a l una matriz de ( n f i l s ) x ( n c o l s ) con v a l o r e s 0 int nfils () const;
// Devuelve e l numero de f i l a s de l a matriz a c t u a l int ncols () const;
// Devuelve e l numero de columnas de l a matriz a c t u a l void poner (int f, int c, double val );
// PRECOND: (0 <= f && f < n f i l s ( ) && 0 <= c && c < n c o l s ( ) ) // Asigna e l v a l o r ( v a l ) a l elemento de l a f i l a ( f )
// y columna ( c ) de l a matriz a c t u a l double obtener (int f, int c) const;
// PRECOND: ( f < n f i l s ( ) && c < n c o l s ( ) )
// Devuelve e l v a l o r d e l elemento de l a f i l a ( f ) // y columna ( c ) de l a matriz a c t u a l
};
Utilice la siguiente estructura para implementar la matriz dispersa, donde hay una lista enlazada ordenada (ascendentemente por número de fila) para acceder por filas, y a partir de un determinado nodo fila, se puede acceder a la lista enlazada ordenada (ascendentemente por número de columna) donde se encuentran los elementos pertenecientes a dicha fila y a la columna especificada en el nodo cuyo valor es distinto de cero. Por ejemplo, la siguiente figura representa la siguiente matriz:
0 2 3 0 40 1 60 3 90 0 50 2 75 1 67 2 83 4 4 nfil ncol filas 40 60 0 90 0 0 0 0 50 0 75 0 0 67 83 0
con las siguientes especificaciones adicionales:
El método obtenerpermite conocer el valor de un determinado elemento de la matriz especificado
por su fila y columna correspondiente. En caso de que dicho elemento no esté almacenado, entonces su valor es cero.
El método poner permite asignar un determinado valor a un determinado elemento de la matriz
especificado por su fila y columna correspondiente.
Solo se almacenarán los elementos de valor distinto de cero, considerando que si un elemento no está almacenado, es que su valor es cero. Si una fila no tiene elementos distintos de cero, el nodo correspondiente a dicha fila no será almacenado.
Si el valor a almacenar es distinto de cero, si el elemento ya existe, se reemplazará su valor, en otro caso se añadirá a la estructura.
Si el valor a almacenar es cero, habrá que eliminar dicho elemento de la estructura si es que existe. Si como consecuencia de ello, la fila queda sin elementos, habrá que eliminar el nodo correspondiente de dicha lista.
4. Se debe diseñar e implementar el tipo abstracto de datosMatrizde números reales en el espacio de nombre
umalcc, junto con las operaciones necesarias para su gestión y tratamiento. Utilice para su implementación
la clase MatrizDispersarealizada en el ejercicio anterior.
class Matriz {
public:
˜ Matriz ();
// Destructor
Matriz ();
// Constructor por Defecto : matriz vacia
Matriz (int nfils , int ncols );
// Constructor e s p e c i f i c o : crea matriz de ( n f i l s ) x ( n c o l s ) con v a l o r e s 0
Matriz (const Matriz& m);
// Constructor de copia
Matriz& operator=(const Matriz& m);
// Operador de Asignacion void clear (int nfils , int ncols );
// Elimina todos l o s elementos de l a matriz actual , y asigna
// a l a matriz a c t u a l una matriz de ( n f i l s ) x ( n c o l s ) con v a l o r e s 0 int nfils () const;
// Devuelve e l numero de f i l a s de l a matriz a c t u a l int ncols () const;
// Devuelve e l numero de columnas de l a matriz a c t u a l void poner (int f, int c, double val );
// PRECOND: (0 <= f && f < n f i l s ( ) && 0 <= c && c < n c o l s ( ) ) // Asigna e l v a l o r ( v a l ) a l elemento de l a f i l a ( f )
// y columna ( c ) de l a matriz a c t u a l double obtener (int f, int c) const;
// PRECOND: ( f < n f i l s ( ) && c < n c o l s ( ) )
// Devuelve e l v a l o r d e l elemento de l a f i l a ( f ) // y columna ( c ) de l a matriz a c t u a l
void sumar (const Matriz& a, const Matriz& b);
// PRECOND: ( ( t h i s != &a)&&( t h i s != &b ) ) ; // Asigna a l a matriz a c t u a l e l r e s u l t a d o de // sumar l a s matrices ( a ) y ( b )
void restar (const Matriz& a, const Matriz& b);
// PRECOND: ( ( t h i s != &a)&&( t h i s != &b ) ) ; // Asigna a l a matriz a c t u a l e l r e s u l t a d o de // r e s t a r l a s matrices ( a ) y ( b )
void multiplicar (const Matriz& a, const Matriz& b);
// PRECOND: ( ( t h i s != &a)&&( t h i s != &b ) ) ; // Asigna a l a matriz a c t u a l e l r e s u l t a d o de // m u l t i p l i c a r l a s matrices ( a ) y ( b )
void escribir () const;
// Muestra en p a n t a l l a e l contenido de l a matriz a c t u a l void leer ();
// Lee de t e c l a d o e l v a l o r de l a matriz actual , // Lee n f i l s , n c o l s y l o s v a l o r e s de l o s elementos
};
5. Implemente un programa principal que permita comprobar el funcionamiento del tipo abstracto de datos Matrizdefinido previamente.
6. Se dispone de un procesador con varias etapas, y de unas determinadas tareas que se ejecutarán pasando sucesivamente por todas las etapas del procesador, desde la primera hasta la última. Como el procesador dispone de varias etapas, es posible que esté procesando simultáneamente diferentes tareas. Por tanto, una tarea sólo podrá pasar a la siguiente etapa si ésta se encuentra libre. La siguiente figura muestra un
procesador con cuatro etapas y dos tareas, la tareaT1 va ejecutándose por la etapae2 y la tareaT2 va
ejecutándose por la etapae4.
procesador
e1 e2 e3 e4
t1 t2
Se debe diseñar la estructura de datos necesaria para representar la información del estado del procesador en cada momento. Para ello, se sigue el esquema mostrado en la siguiente figura. Como se puede observar
cada etapa se representa con dos elementos, una lista de nodos intermedios con tantos nodos como réplicas (véase más adelante) haya de la etapa (en el ejemplo sólo se muestra una réplica por cada etapa) y los correspondientes nodos de etapa. Cada nodo de etapa contendrá su identificador, el número de la tarea que está ejecutando (un número cero indica que está libre, es decir, no está ejecutando ninguna tarea), y un puntero al primer nodo de la lista de nodos intermedios de la siguiente etapa. También se puede
observar que la tareaT1 se está ejecutando en la etapa 2 y la tareaT2 se está ejecutando en la etapa 4.
0 1 1 2 0 3 2 4 procesador
Es posible que en un determinado momento interese ampliar la potencia de una determinada etapa. Para ello, se replicará dicha etapa haciendo tantos duplicados de la misma como se desee. Así mismo, es posible que interese reducir la potencia de una determinada etapa, para ello se eliminarán réplicas de la misma.
Defina el TADProcesador que implemente la estructura de datos especificada anteriormente, y que
propor-cione los siguientes métodos públicos, así mismo, también se deberá implementar un programa principal que permita su utilización:
a) ElConstructorrecibe el número de etapas que tiene un determinado procesador, y crea la estructura
base de étapas sin replicación y todas en estado inicial libre, como se muestra en la siguiente figura
para un procesador de 4 etapas: 0 1 0 2 0 3 0 4 procesador
b) ElDestructorlibera todos los recursos asociados al objeto que está siendo destruido.
c) El métodoMostrar muestra en pantalla la estructura interna de un procesador. Por ejemplo, para
la figura anterior: Etapa: 1 Replica: libre Replica: libre Etapa: 2 Replica: tarea 1 Replica: tarea 2 Etapa: 3 Replica: libre Etapa: 4 Replica: libre
d) Un métodoReplicar, que se usará para ampliar la potencia de una determinada etapa del procesador
actual. Recibe como parámetros el identificador de la etapa a replicar y el número de réplicas que
deseamos añadir. Las réplicas añadidas tendrán el estado iniciallibre(no tienen asignadas la ejecución
de ninguna tarea).
Las réplicas se añadirán a la estructura añadiendo (en cualquier posición SALVO AL PRINCIPIO) nodos a la lista de nodos intermedios correspondiente a la etapa y nodos de etapa apuntados desde los nodos intermedios añadidos. Como se puede observar, todas las réplicas añadidas deben apuntar al primer nodo intermedio de la etapa siguiente (salvo en la última etapa). La siguiente figura muestra el resultado de añadir dos réplicas de la etapa 2 a la figura anterior:
0 1 1 2 0 3 2 4 0 2 0 2 procesador
0 1 1 2 0 3 2 4 0 2 0 2 0 1 procesador
e) Un método para Compactar que se usará para disminuir el número de réplicas de una etapa del
procesador actual. Para ello, recibe como parámetro el identificador de la etapa a compactar y
elimina todas las réplicas de dicha etapa cuyo estado sea libre (no esté ejecutando ninguna tarea).
Al compactar etapas habrá que tener en cuenta que: De cada etapa deberá quedar al menos una réplica.
Las réplicas que estén ejecutando alguna tarea no pueden ser eliminadas.
No se podrá liberar la memoria ocupada por el primer nodo de la lista de nodos intermedios de una etapa (pues sirve de enlace entre una etapa y la siguiente). En caso de que la compactación requiera eliminar la primera réplica de una etapa (porque esté libre), el puntero al nodo de etapa del primer nodo de la lista de nodos intermedios pasará a apuntar a un nodo de etapa que permanezca tras la compactación. Por ejemplo, para la siguiente figura:
0 1 0 2 0 3 0 4 2 2 1 2 0 1 procesador
la siguiente figura es el resultado de compactar la etapa 2 de la figura anterior: 0 1 0 3 0 4 2 2 1 2 0 1 procesador
f) El métodoAvanzarEvaluacionintenta avanzar una tarea de una determinada etapa a la siguiente.
Para ello, recibe como parámetro el número de tarea (distinto de cero) que pretende avanzar a la siguiente etapa.
Si la tarea es nueva, buscará una réplica libre de la primera etapa del procesador. Si no hay réplicas libres en esta primera etapa, entonces lanzará una excepción.
Si la tarea se está ejecutando en la última etapa del procesador, entonces la tarea habrá terminado su ejecución, y su número desaparecerá de la estructura.
En otro caso, intenta avanzar la tarea desde la réplica de la etapa en que se encuentra ejecutándose
hasta alguna réplica libre de la siguiente etapa. Si no hay ninguna réplica libre de la siguiente
etapa, entonces lanzará una excepción.
g) Así mismo, también deberá ser posible realizar la copia y asignación (duplicación) de la estructura
de datos que representa a un determinado procesador.
Tema 4: Introducción a la Programación Orientada a Objetos
1. Para calcular los sueldos de cada empleado de una factoría, se diseña la siguiente jerarquía de clases polimórficas: AgVentas AgVentas_A AgVentas_B Empleado Directivo Directivo_A Directivo_B Factoria
La clase polimórficaEmpleadorepresenta un empleado general de una factoría, tiene un constructor
que permite crear un objeto con el nombre (string) del empleado recibido como parámetro, y
proporciona los siguientes métodos públicosvirtuales:
• clone(): devuelve un puntero a un nuevo objeto creado como copia del objeto actual.
• sueldo(): calcula y devuelve el sueldo del empleado. En caso de no tener información suficiente para calcular el sueldo, entonces devolverá 0.
• nombre(): devuelve el nombre del objeto empleado actual.
La clase polimórfica AgVentas representa un agente de ventas general, empleado de una factoría,
tiene un constructor que permite crear un objeto con el nombre (string) del empleado recibido
como parámetro, y proporciona los siguientes métodos públicosvirtuales:
• clone(): devuelve un puntero a un nuevo objeto creado como copia del objeto actual.
• borrar_ventas(): reinicia a cero la cantidad total de ventas que acumula este agente de ventas. • anyadir_ventas(x): permite añadir una cantidad deeuros recibida como parámetro a la
canti-dad total de ventas que acumula este agente de ventas.
• ventas(): devuelve la cantidad total de ventas que acumula este agente de ventas.
La clase polimórficaAgVentas_Arepresenta un agente de ventas de claseA, empleado de una factoría,
tiene un constructor que permite crear un objeto con el nombre (string) del empleado recibido como
parámetro, y proporciona los siguientes métodos públicosvirtuales:
• clone(): devuelve un puntero a un nuevo objeto creado como copia del objeto actual.
• sueldo(): redefine este método para calcular y devolver el sueldo de este tipo de agente de ventas, según la siguiente ecuación:
sueldo= 2000.0 +10.0×total_ventas 100.0
La clase polimórficaAgVentas_Brepresenta un agente de ventas de claseB, empleado de una factoría,
tiene un constructor que permite crear un objeto con el nombre (string) del empleado recibido como
parámetro, y proporciona los siguientes métodos públicosvirtuales:
• clone(): devuelve un puntero a un nuevo objeto creado como copia del objeto actual.
• sueldo(): redefine este método para calcular y devolver el sueldo de este tipo de agente de ventas, según la siguiente ecuación:
sueldo= 1000.0 +5.0×total_ventas 100.0
La clase polimórfica Directivo representa un directivo general, empleado de una factoría, tiene
un constructor que permite crear un objeto con el nombre (string) del empleado recibido como
parámetro, y proporciona los siguientes métodos públicosvirtuales:
• clone(): devuelve un puntero a un nuevo objeto creado como copia del objeto actual.
La clase polimórficaDirectivo_Arepresenta un directivo de claseA, empleado de una factoría, tiene
un constructor que permite crear un objeto con el nombre (string) del empleado recibido como
• clone(): devuelve un puntero a un nuevo objeto creado como copia del objeto actual.
• sueldo(): redefine este método para calcular y devolver el sueldo de este tipo de directivos, según la siguiente ecuación:
sueldo = 5000.0
La clase polimórficaDirectivo_Brepresenta un directivo de claseB, empleado de una factoría, tiene
un constructor que permite crear un objeto con el nombre (string) del empleado recibido como
parámetro, y proporciona los siguientes métodos públicosvirtuales:
• clone(): devuelve un puntero a un nuevo objeto creado como copia del objeto actual.
• sueldo(): redefine este método para calcular y devolver el sueldo de este tipo de directivos, según la siguiente ecuación:
sueldo = 3000.0
La clase polimórficaFactoriarepresenta una factoría con un máximo de 100 empleados, su
construc-tor por defecto permite crear un nuevo objeto de claseFactoriasin ningún empleado, y proporciona
los siguientes métodos públicosvirtuales:
• clone(): devuelve un puntero a un nuevo objeto creado como copia del objeto actual.
• anyadir_empleado(e, ok): intenta añadir el empleado que recibe como primer parámetro (de entrada) a la lista de empleados de la factoría actual. Si la operación es posible o no, entonces
devuelvetrue ofalse, respectivamente, en el segundo parámetro (de salida).
• sueldos(): muestra en pantalla tanto el nombre como el sueldo de cada empleado de la factoría.
Finalmente, el programa principal creará un objeto de la clase Factoria, le añadirá empleados
(Directivo_A,Directivo_B,AgVentas_AyAgVentas_B) y ventas acumuladas a los agentes de ven-tas, y calculará sus sueldos. Así mismo, tambien probará que la clonación de la factoría funciona adecuadamente.
2. Se desea simular el comportamiento de una serie de vehículos, por lo que se establece la siguiente jerarquía de clases:
Vehiculo
Bicicleta Automovil
Todo objeto de la clase base polimórficaVehiculodebe guardar en su estado la siguiente información
y definir el siguiente constructor:
• ident: identificador del vehículo (cadena de caracteres).
• distancia: la distancia recorrida por el vehículo con respecto al punto de partida (origen) del
mismo (unsigned).
• Vehiculo(i): inicializa el identificador del vehículo coniy sudistanciaa cero.
Además, el comportamiento de los objetos Vehículoqueda definido por los siguientes métodos
pú-blicos virtuales:
• id(): devuelve el indentificador del vehículo
• consultar_dist(): devuelve ununsignedcon la distancia recorrida por el vehículo • estacionar(): establece la distancia recorrida por el vehículo en 0 (origen)
• tiene_energia(): indica si el vehículo tiene energía (función lógica). Debe devolver siempre true
• mover(): incrementa en 1 el valor de la distancia recorrida por el vehículo. • clone(): devuelve un puntero a un objetoVehiculo, copia del vehículo actual
Además, la clase Vehículo proporciona a sus clases derivadas los siguientes métodos protected,
para poder manipular adecuadamente su estado interno:
La clase derivada polimórficaAutomovilañade los siguientes atributos y define el siguiente construc-tor:
• DPL: constante simbólica static, de tipo unsigned, que indica la distancia que el automóvil
recorre por litro de combustible (= 50).
• deposito: atributo unsigned que guarda el número de litros de combustible del depósito del automóvil.
• Automovil(i): inicializa el identificador del automóvil ai, sudistanciaa 0 y sudepositoa 0.
Además, el comportamiento de los objetos Automovil queda definido por los siguientes métodos
públicos virtuales:
• tiene_energia(): redefine el método de la clase base, devolviendotrue si la cantidad
almace-nada en eldepositoes mayor que 0.
• mover(): redefine el método de la clase base, de tal forma que si el automóvil tiene energía,
entonces se mueve una distancia igual al valor deDPL, es decir, se incrementa la distancia recorrida
actual sumándole a la misma el valor almacenado en la constante miembroDPL.
• repostar(ltr): incrementa la cantidad de combustible almacenada en eldepositodel automóvil
enltrlitros.
• clone(): devuelve un puntero a un objetoAutomovil, copia del automóvil actual.
La clase derivada polimórficaBicicletaañade los siguientes atributos y define el siguiente
construc-tor:
• NUM_PLATOS: constante simbólicastatic, de tipounsigned, indicando el número de platos que tiene la bicicleta.
• plato: ununsignedque indica el plato que tiene puesto en este momento la bicicleta (a mayor tamaño de plato, mayor será su desplazamiento cuando la bicicleta se mueva).
• Bicicleta(i): inicializa el identificador de la bicicleta ai, sudistanciaa 0 y suplatoa 0.
Además, el comportamiento de los objetos Bicicleta queda definido por los siguientes métodos
públicos virtuales:
• mover(): redefine el método de la clase base, de tal forma que la bicicleta se mueve una distancia
igual al valor deplato + 1, es decir, se incrementa la distancia recorrida actual sumándole a la
misma el valor deplato + 1.
• cambiar(): cambia el valor delplato, sumándole 1 y aplicando posteriormente% NUM_PLATOS
(el valor del plato siempre estará entre0yNUM_PLATOS - 1).
• clone(): devuelve un puntero a un objetoBicicleta, copia de la bicicleta actual.
El programa principal debe definir el tipo Vehiculoscomo un tipo array de NUM_VEHICULOS = 4
punteros a objetos de la claseVehiculo.
Implementar el procedimiento viajar(v, d, t), que recibe un puntero a un objeto de la clase
Vehiculo, ununsignedcon ladistanciatotal a recorrer por el vehículo, y devuelve, a través de un
parámetro de salida el tiempo(“minutos”) que el vehículo ha tardado en llegar a su destino(si ha
tenido energía suficiente para llegar). Este algoritmo debe proceder de la siguiente manera:
a) Estacionar el vehículo (es decir, inicializar la distancia recorrida a 0).
b) Inicializar eltiempoa 0.
c) Mientras que el vehículo tenga energía y su distancia recorrida sea menor que la distancia
solicitada, el vehículo debe moverse (para ello, el procedimiento debe invocar la función miembro mover()del objetoVehiculo) ytiempose incrementa en 1.
Implementar el programa principal (main), con las siguientes características:
• Declara un array mis_vehiculosde tipoVehiculos.
• Crea un objetoAutomovil, con identificador"5555JJJ"y 50 litros de gasolina y ponemis_vehiculos[0]
apuntando a él.
• Crea un objeto Bicicleta, con identificador "6666JJJ"y pone mis_vehiculos[1]apuntando
a él.
• Crea un objetoBicicleta, con identificador"7777JJJ", cambia su plato y ponemis_vehiculos[2]
apuntando a él.
• Crea un objeto Bicicleta, con identificador "8888JJJ", cambia su plato dos veces y pone
• Para todos los vehiculos que se encuentran enmis_vehiculos, debe calcular el tiempo de
dura-ción del viaje para una distancia recorrida de destino 1000 invocando al procedimientoviajar
y, en caso de que el vehículo tuviera energía suficiente, escribe ese tiempo por pantalla (en caso
contrario, se indica con un mensaje por pantalla: El vehículo x no ha podido llegar a su
destino por falta de energía) • Un ejemplo de ejecución podría ser:
El vehículo 5555JJJ no ha podido llegar a su destino por falta de energía Tiempo vehículo 6666JJJ: 1000 minutos
Tiempo vehículo 7777JJJ: 500 minutos Tiempo vehículo 8888JJJ: 334 minutos
3. Dada la jerarquía de clases deVehiculodel ejercicio anterior, se debe desarrollar la claseno-polimórfica
Parkingpara gestionar un parking con un máximo deMAX = 100vehículos (de cualquier tipo) estacionados en él.
Los objetos de la claseParkingdeben almacenar en su estado la siguiente información:
• MAX: constante simbólica static con el máximo (= 100) de vehículos que pueden estacionarse
en el parking.
• parking: un array deMAXpunteros a objetos de la claseVehiculo.
• n_v: número de vehículos estacionados en el parking.
Además, la claseParkingdebe suministrar los siguientes métodos, constructores, etc.públicos:
• Parking(): inicializa el número de vehículos estacionados en el parking a 0.
• Parking(otro_parking): constructor de copia de la clase: copia (clona) todos los vehículos
estacionados en otro_parkingal parking actual.
• ~Parking(): destructor de la clase: libera todos los vehículos almacenados en el parking (los destruye).
• operator=(otro_parking): operador de asignación para la claseParking.
• anyadir(v, ok): recibe como parámetro de entrada v, un puntero a un objeto de la clase Vehiculo. Si hay espacio en el parking para estacionar un nuevo vehículo, entoncesvse añade al final de la lista de vehículos estacionados en el parking y el número de vehículos estacionados se
incrementa en 1; finalmente, se debe invocar al método deestacionarsobre este nuevo vehículo
estacionado (para que su distancia recorrida se ponga a 0);okdebe ponerse atrueen ese caso.
Si no hay espacio para estacionar en el parking, se devuelve falsea través deok.
• mostrar(): muestra por pantalla los identificadores de todos los vehículos estacionados en el parking.
• extraer(id): busca en la lista de vehículos almacenados en el parking el vehículo con
idenfifi-cadorid. Si lo encuentra, debe extraer el vehículo del parking y devolver un puntero al objeto
vehículo extraído. Si no lo encuentra, entonces devuelveNULL.
Se aconseja, además, implementar los siguientes métodos privados de la clase Parking:
• buscar(id): devuelve la posición del array parking que contiene un puntero apuntando al
vehículo con identificadorid, si éste está estacionado en el parking. Si no, devuelve una posición
fuera de rango (por ejemplo, eln_v).
• copiar(otro_parking): copia todo el estado deotro_parking(esto es, clona todos los vehículos
almacenados en él y copia sun_v) en el objeto actual. Nota: deben clonarse todos los vehículos
del objetootro_parkingpara que el parking actual trabaje con copias de los mismos.
• destruir(): destruye todos los vehículos almacenados en el parking.
Debe implementarse un programa principal que declare un objeto de la clase Parking y “pruebe”
toda su funcionalidad: añada vehículos de distinto tipo (vehículos genéricos, automóviles y bicicletas) al parking, los muestre, los extraiga, haga una copia completa del parking, etc.
Tema 5: Colecciones
1. Diseñe un programa que utilice el tipovector de la biblioteca estándar para almacenar las personas de
una agenda, donde por cada persona se almacena el nombre y el teléfono. La agenda se gestiona mediante la siguientes operaciones:
Añadir los datos de una persona a la agenda, de tal forma que si la persona ya existe, entonces se actualiza su número de teléfono, y en otro caso, se añade la nueva persona y su teléfono a la agenda. Mostrar todos los datos de la agenda.
Mostrar los datos de una determinada persona, a partir de su nombre recibido como parámetro. En caso de que no exista en la agenda ninguna persona con dicho nombre, entonces se mostrará un mensaje de error.
Borrar los datos de una determinada persona, a partir de su nombre recibido como parámetro. En caso de que no exista en la agenda ninguna persona con dicho nombre, entonces se mostrará un mensaje de error.
2. Realice el ejercicio anterior, utilizando el TADPersonadefinido en la práctica 6, e implementando el TAD
Agenda de la misma práctica convectoren vez de con una lista enlazada.
3. Diseñe un programa que lea y almacene en un vectorde la biblioteca estándar las ventas realizadas por
unos agentes de ventas. Leerá el nombre y el total de ventas que ha realizado, hasta leer un nombre de agente vacío. Posteriormente se eliminarán del vector aquellos agentes cuyas ventas sean inferiores a la media de las ventas realizadas. Finalmente se mostrará el contenido del vector.
4. Diseñe un programa que lea dos matrices de números reales de tamaños arbitrarios (primero leerá las dimensiones y posteriormente los elementos de la matriz) y muestre el resultado de multiplicar ambas
matrices. Las matrices se almacenarán en vectores de dos dimensiones (utilizando el tipo vector de la
biblioteca estándar).
5. Diseñe un programa que lea una expresión aritmética que contiene llaves{}, paréntesis()y corchetes[]
y compruebe si éstos se encuentran correctamente balanceados o no. Por ejemplo la siguiente expresión
3 + 5∗([4]−67) + [(7)]se encuentra correctamente balanceada, donde los posibles casos de error son los
siguientes:
Un símbolo de apertura no se corresponde con su correspondiente símbolo de cierre. Por ejemplo:
3 + 5∗([4]−67] + [(7)]
Para un determinado símbolo de apertura, no existe el correspondiente símbolo de cierre. Por ejemplo:
(3 + 5∗([4]−67 + [(7)])
Para un determinado símbolo de cierre, no existe el correspondiente símbolo de apertura. Por ejemplo:
Prácticas de Laboratorio
Práctica 1: Almacenamiento Persistente de Datos
1. Diseñe un programa que gestione una agenda que almacene información sobre personas (nombre y edad), permita añadir, modificar y eliminar personas desde el teclado, así como mostrar el contenido de la agenda. Adicionalmente, el programa permitirá cargar el contenido de la agenda desde un fichero, así como guardar el contenido de la agenda a un fichero.
Se diseñarán versiones para trabajar con tres formatos de ficheros diferentes (donde los símbolos y ←
-representan el espacio en blanco y el fin de línea respectivamente):
Opción (A) Opción (B) Opción (C)
nombre_apellidos edad ← -nombre_apellidos edad ← -· -· -· nombre apellidos ← -edad ← -nombre apellidos ← -edad ← -· -· -·
nombre apellidos edad ←
-nombre apellidos edad ← -· -· -·
Nótese que en la primera opción (A), el nombre de la persona no contiene espacios en blanco, mientras que en las siguientes opciones (B y C), si es posible que el nombre de la persona contenga espacios en blanco.
El programa mostrará un menú iterativo para poder seleccionar las acciones deseadas por el usuario del programa, tal como:
# include <iostream> # include <fstream> # include <string> # include <array> # include <cctype> using namespace std; struct Persona { string nombre ; unsigned edad ; };
const unsigned MAX = 100;
typedef array<Persona , MAX> APers ;
struct Agenda {
unsigned nelms ; APers elm ; };
// . . . a completar por e l alumno . . . . char menu ()
{
char op;
cout << endl;
cout << "C. Cargar Agenda desde Fichero " << endl;
cout << "G. Guardar Agenda en Fichero " << endl;
cout << "M. Mostrar Agenda en Pantalla " << endl;
cout << "A. Anadir Persona a la Agenda " << endl;
cout << "X. Fin " << endl;
do {
cout << endl << " Opcion : ";
cin >> op;
op = char( toupper (op ));
} while (!(( op == 'C')||(op == 'G')||(op == 'M')||(op == 'A')||(op == 'X')));
cout << endl; return op; } int main () { Agenda ag; char op; inic_agenda (ag ); do { op = menu (); switch (op) { case 'C': cargar_agenda (ag );
break; case 'G': guardar_agenda (ag ); break; case 'M': escribir_agenda (ag ); break; case 'A': nueva_persona (ag ); break; } } while (op != 'X'); }
Práctica 2: Tipos Abstractos de Datos (I)
1. Diseñe e implemente un TAD para números racionales. Se deberán seguir las siguientes consideraciones: Los números racionales se representan mediante fracciones, donde tanto el numerador como
denomi-nador son de tipoint).
Las fracciones se representarán en todo momento normalizadas (simplificadas):
• Es recomendable implementar un método privado de simplificación de la fracción mediante el cálculo del máximo común divisor (m.c.d.) del numerador y el denominador y su posterior división por dicho m.c.d.
Para calcular el máximo común divisor de dos numeros enteros positivosnym, el algoritmo de
Euclides funciona como se indica a continuación:
a) Sin < m, entonces se intercambian los valores denym(para asegurarnos quensiempre sea mayor o igual quem).
b) Si el valor demes distinto de0, entonces sear el resto de la división entera entren ym; después modificamos los valores denymde la siguiente forma:ntoma ahora el valor demymtoma ahora el valor der (el resto de la división entera entren y mcalculado anteriormente), y se repite este proceso especificado hasta que el valor demsea igual a0.
c) Finalmente, cuando el proceso iterativo acaba, el valor denes el máximo común divisor de ambos números.
• Para simplificar la determinación del signo de la fracción puede asumirse que el denominador de la fracción es siempre positivo (por lo que una fracción de signo negativo tendrá un numerador de signo negativo y un denominador de signo positivo).
El cero se guardará siempre en su forma canónica 0/1.
Por defecto, un número racional debe asignarse a cero cuando se crea. Debe evitarse en todo momento la asignación de cero a un denominador.
Un determinado método permitirá comprobar si un determinado número racional se encuentra en estado de error. Un denominador igual a cero (0) se considera un estado de error.
Debe poder ser posible crear números racionales especificando su numerador y denominador, como sólamente especificando su numerador (en este último caso, se considerará un denominador igual a 1). class Racional { public: Racional () ; // Construye e l numero r a c i o n a l 0/1 Racional (int n) ; // Construye e l numero r a c i o n a l n/1
Racional (int n, int d) ;
// Construye e l numero r a c i o n a l n/d bool fail () const;
// Devuelve t r u e s i e l numero r a c i o n a l a c t u a l e s t a en estado erroneo void multiplicar (const Racional& r1 , const Racional& r2 );
// Asigna a l numero r a c i o n a l a c t u a l e l r e s u l t a d o de // m u l t i p l i c a r l o s numeros r a c i o n a l e s ( r1 ) y ( r2 ) void escribir () const;
// Muestra en p a n t a l l a e l v a l o r d e l numero r a c i o n a l a c t u a l void leer (); // Lee de t e c l a d o e l v a l o r d e l numero r a c i o n a l a c t u a l private: void normalizar (); };
2. Diseñe un programa que permita utilizar el TAD especificado en el ejercicio anterior.
3. Añada de forma incremental los siguientes métodos públicos al TADRacional realizado anteriormente:
class Racional {
public:
// . . .
void dividir (const Racional& r1 , const Racional& r2 );
// Asigna a l numero r a c i o n a l a c t u a l e l r e s u l t a d o de // d i v i d i r l o s numeros r a c i o n a l e s ( r1 ) y ( r2 )
void sumar (const Racional& r1 , const Racional& r2 );
// Asigna a l numero r a c i o n a l a c t u a l e l r e s u l t a d o de // sumar l o s numeros r a c i o n a l e s ( r1 ) y ( r2 )
void restar (const Racional& r1 , const Racional& r2 );
// Asigna a l numero r a c i o n a l a c t u a l e l r e s u l t a d o de // r e s t a r l o s numeros r a c i o n a l e s ( r1 ) y ( r2 )
bool igual (const Racional& r1) const;
// Devuelve t r u e s i e l numero r a c i o n a l a c t u a l es i g u a l a ( r1 ) bool menor (const Racional& r1) const;
// Devuelve t r u e s i e l numero r a c i o n a l a c t u a l es menor que ( r1 )
};
4. Modifique el programa que utiliza el TADRacional especificado anteriormente para que utilice los nuevos