PRÁCTICA NΊ 3: 1 sesión

(del 26 de Marzo al 30 de Marzo de 2001)

Tipos Abstractos de Datos. Trabajo con Vectores y Matrices

0. Objetivo

El objetivo de esta práctica es la realización de dos programas. Uno para trabajar con vectores y otro para operar con matrices ambos con distintos tipos de datos: enteros y complejos. Para ello, el profesor dará al alumno dos programas objeto en C++ con un solo fichero de cabecera (c_entero.o, c_comple.o, numero.h) con los que deberán "linkar" los programas principales sin modificaciones.

1. Tipos Abstractos de Datos

Un tipo abstracto de datos (TAD) es, básicamente, una colección de valores junto con unas determinadas operaciones definidas sobre ellos. Para el usuario del tipo abstracto de datos sólo importan los valores que puedan guardar las variables asociadas al TAD y las operaciones de manipulación del mismo, dejando para el programador la tarea de la implementación de la estructura, tipo de dato o clase de C++ que soporte el TAD y de las operaciones relacionadas con él.

En esta práctica vamos a limitarnos a utilizar unos determinados tipos abstractos de datos para implementar algunas operaciones habituales sobre vectores y sobre matrices.

2. Clases para la especificación de los tipos abstractos de datos "CoMPLEJO" y "Entero"

Clase para la manipulación del tipo "complejo". c_comple.o (fuentes de la implementacion de la clase)

Supongamos el tipo abstracto de datos ‘Complejo’, capaz de almacenar valores complejos (con componentes reales.) Este tipo abstracto de datos tiene asociadas las siguientes operaciones:

Void Iniciar_Valor (void);

Que inicia el contenido de la parte Real y de la parte Compleja del numero complejo con información pedida al usuario por teclado.

void Ver_Valor (void);

Que muestra el valor del número complejo contenido en el objeto.

void Sumar_Valor (Numero a);

Que suma el valor del numero complejo ‘a’ sobre el propio objeto.

void Restar_Valor (Numero a);

Que resta el valor del numero complejo ‘a’ del valor contenido en el propio objeto.

void Multiplicar_Valor (Numero a);

Que multiplica el valor del numero complejo ‘a’ sobre el contenido en el propio objeto.

void Dividir_Valor (Numero a);

Que divide el valor complejo contenido en el objeto por el valor de ‘a’ y guarda el resultado en el propio objeto.

La clase Numero está definida en el programa de cabecera "Numero.h". Las operaciones de manipulación estarán implementados en el programa objeto "c_comple.o".

Clase para la manipulación del tipo "entero". c_entero.o (fuentes de la implementacion de la clase)

Supongamos el tipo abstracto de datos ‘Entero’, capaz de almacenar valores enteros. Este tipo abstracto de datos tiene asociadas las siguientes operaciones:

Void Iniciar_Valor (void);

Que inicia el contenido del objeto pidiendo la información por teclado al usuario.

void Ver_Valor (void);

Que muestra el valor entero contenido en el objeto.

void Sumar_Valor (Numero a);

Que suma el valor del numero entero ‘a’ sobre el propio objeto.

void Restar_Valor (Numero a);

Que resta el valor del numero entero ‘a’ del valor contenido en el propio objeto.

void Multiplicar_Valor (Numero a);

Que multiplica el valor del numero entero ‘a’ sobre el contenido en el propio objeto.

void Dividir_Valor (Numero a);

Que divide el valor entero contenido en el objeto por el valor de ‘a’ y guarda el resultado en el propio objeto (resultado entero).

La clase Numero está definida en el programa de cabecera "Numero.h". Las operaciones de manipulación estarán implementados en el programa objeto "c_entero.o".

3. Trabajo con Vectores

Se pide realizar un programa en C++ que permita realizar algunas operaciones sencillas con vectores, independientemente del tipo de valores almacenados en ellos.

La cabecera del programa será la siguiente:

#include "numero.h"

const int MAX = 20;

/*

* Definimos el vector como una estructura que contine:

* Info -> informacion que guardamos en el vector

* N_elem -> De todos los valores guardados en info solo consideramos

* ‘N_elem’ como validos.

*/

struct Vector

{

Numero Info[MAX];

int N_elem;

};

El programa deberá contener necesariamente los siguientes subprogramas:

void Introducir_Vector (Vector & vec);

Subprograma que pedirá el número de elementos del vector (N_elem) y los valores contenidos en el vector.

void Ver_Vector (Vector vec);

Subprograma que mostrará por pantalla los valores almacenados en el vector (desde 0 hasta N_elem – 1).

bool Sumar_Vector (Vector ve1; Vector ve2; Vector & res);

Función que sumará los vectores ‘ve1’ y ‘ve2’ poniendo el resultado en ‘res’ y devolviendo true. Si los vectores no se pudieran sumar (número de elementos distinto) devolverá false.

bool Multiplica_Escalar (Vector ve1; Vector ve2; Numero & res);

Función que multiplicará escalarmente los vectores ‘ve1’ y ‘ve2’ poniendo el resultado en ‘res’ y devolviendo TRUE. Si los vectores no se pudieran multiplicar (número de elementos distinto) devolverá FALSE.

El programa principal se limitará a:

1.- Pedir dos vectores, vect1 y vect2.

2.- Mostrar los vectores vect1 y vect2 por pantalla.

3.- Multiplicar escalarmente los vectores y mostrar el resultado por pantalla. Si los vectores no se pueden multiplicar, informará de ello al usuario.

4. Trabajo Con Matrices

Realizar también un programa que trabaje con matrices, independientemente del tipo de valores que contengan.

La cabecera del programa será la siguiente:

#include "numero.h"

const int MAX = 20;

/*

* Definimos el vector como una estructura que contine:

* Info -> informacion que guardamos en el vector

* N_fil, N_col -> De todos los valores guardados en info solo consideramos

* ‘N_fil x N_col’ como validos.

*/

struct Matriz

{

Numero Info[MAX];

int N_fil, N_col;

};

El programa deberá contener los siguientes subprogramas:

void Introducir_Matriz (Matriz & mat);

Subprograma que pedirá el número de filas y de columnas de la matriz y los valores contenidos en la matriz.

void Ver_Matriz (Matriz mat);

Procedimiento que mostrará por pantalla los valores almacenados en la matriz.

bool Sumar_Matrices (Matriz ma1; Matriz ma2; Matriz & res);

Función que sumará las matrices ‘ma1’ y ‘ma2’ poniendo el resultado en ‘res’ y devolviendo TRUE. Si las matrices no se pudieran sumar (número de filas o de columnas distintas) devolverá FALSE.

bool Restar_Matrices (Matriz ma1; Matriz ma2; Matriz & res);

Función que restará las matrices ‘ma1’ y ‘ma2’ poniendo el resultado en ‘res’ y devolviendo TRUE. Si las matrices no se pudieran restar (número de filas o de columnas distintas) devolverá FALSE.

Function Multiplicar_Matrices (Matriz ma1; Matriz ma2; Matriz & res);

Función que multiplicará las matrices ‘ma1’ y ‘ma2’ poniendo el resultado en ‘res’ y devolviendo TRUE. Si las matrices no se pudieran multiplicar (número de columnas de ‘ma1’ distinto del número de filas de ‘ma2’) devolverá FALSE.

El programa principal se limitará a:

1.- Pedir dos matrices, matriz1 y matriz2.

2.- Mostrar las matices matriz1 y matriz2 por pantalla.

3.- Sumar las matrices y mostrar el resultado por pantalla. Si las matrices no se pueden sumar, informará de ello al usuario.

4.- Restar las matrices y mostrar el resultado por pantalla. Si las matrices no se pueden restar, informará de ello al usuario.

5.- Multiplicar las matrices y mostrar el resultado por pantalla. Si las matrices no se pueden multiplicar, informará de ello al usuario.

En ningún caso se pide la utilización de menús ni opciones en estos programas.

En esta práctica, se trata, por un lado, de realizar un programa debidamente estructurado, mediante la utilización de subprogramas adecuados, y por otro, empezar a utilizar de forma estricta las normas de estilo de la Guía de C++. Las prácticas que no cumplan las normas de estilo serán mal calificadas.

En estos programas hay que tener en cuenta que deben linkar y funcionar correctamente tanto con el tipo Numero complejo, y el programa objeto c_comple.o asociado, como con el tipo Numero Entero y el programa objeto c_entero.o asociado, de manera que cualquier proceso de manipulación de los tipos Numero Complejo y Numero Entero se debe realizar a través de las operaciones definidas en la clase Numero contenida en el fichero de cabecera Numero.h, de forma que en los programas no aparezca ningún detalle que indique cómo se ha representado el tipo Numero Complejo o el tipo Numero Entero. Las soluciones que no cumplan este requisito serán consideradas incorrectas.

5. Trabajos Opcionales

Se proponen como trabajos opcionales:

En el programa de trabajo con vectores

Añadir la siguiente función:

bool Multiplicar_Vectorial (Vector ve1; Vector ve2; vector & res);

Función que multiplicará vectorialmente los vectores ‘ve1’ y ‘ve2’ poniendo el resultado en ‘res’ y devolviendo TRUE. Si los vectores no se pudieran multiplicar (número de elementos distinto) devolverá FALSE.

Y al programa principal el siguiente punto:

4.- Multiplicar vectorialmente los vectores y mostrar el resultado (p_vect) por pantalla. Si los vectores no se pueden multiplicar, informará de ello al usuario.

En el programa de trabajo con matrices

Añadir las siguientes funciones:

bool Determinante_Matriz (Matriz mat; Numero & res);

bool Adjunta_Matriz (Matriz mat; Matriz & res);

bool Inversa_Matriz (Matriz mat; Matriz & res);

y al programa principal el punto:

6.-Calcular la Inversa de la matriz matriz1 y calcular y mostrar por pantalla el resultado de multiplicar matriz1 por su inversa.

3. Entrega de programas

Al finalizar la siguiente sesión de prácticas se entregarán al profesor dos programas principales en C++ llamados: ‘vector.cpp’ y ‘matriz.cpp’ que cumpla los requisitos reseñados en el enunciado de la práctica.

 

 

 

 

 

 

 

 

ENTREGA DE PROGRAMAS: Al iniciar la sesión de prácticas siguiente.

 

Cálculo del determinante

El cálculo del determinante se puede hacer de diversas maneras, pero se aconseja utilizar el método del desarrollo por filas o columnas.

Este método nos dice que el valor del determinante de una matriz cuadrada (n x n) es igual a la suma de los productos de los elementos de una columna (o fila) por los respectivos adjuntos.

Se llama adjunto, Aij, de un elemento aij perteneciente a una matriz, al producto del menor complementario del elemento por (-1)i+j. Y el menor complementario de un elemento aij es el determinante de orden n-1 que se obtiene eliminando la fila i y la columna j, del determinante original de orden n.

Así un determinante general de orden n será:

para cualquier valor de j.

El determinante de una matriz de 1x1 es el propio elemento almacenado en la matriz.

Con esta definición de determinante, es fácil construir una función recurrente que calcule el determinante, que contenga como condición de final el determinante 'trivial' (determinante de orden 1). Y como caso general el desarrollo por la fila o la columna 1.

Para la utilización de este método general de resolución de determinantes quizá sería necesaria la implementación de un subprograma que ‘reduzca’ de una matriz la fila ‘i’ y la columna ‘j’ (elimine de la matriz los elementos correspondientes a la fila ‘i’ y la columna ‘j’.)