# PR 3 [Volver a la página principal de "Fundamentos de la Programación"](../README.md) **Índice** - [PR 3](#pr-3) - [16. Tipos de datos estructurados: tabla](#16-tipos-de-datos-estructurados-tabla) - [16.1 Sintaxis para la declaración (definición) de tablas](#161-sintaxis-para-la-declaración-definición-de-tablas) - [16.1.1 Ejemplo](#1611-ejemplo) - [16.1.2 Acceso a los elementos de una tabla](#1612-acceso-a-los-elementos-de-una-tabla) - [16.1.3 Ejemplo](#1613-ejemplo) - [16.2 Inicialización de una tabla](#162-inicialización-de-una-tabla) - [16.3 Carga de datos a partir de una secuencia](#163-carga-de-datos-a-partir-de-una-secuencia) - [16.4 Recorrido de una tabla](#164-recorrido-de-una-tabla) - [16.4.1 Ejemplo: lectura y recurrido](#1641-ejemplo-lectura-y-recurrido) - [16.5 Búsqueda de un elemento en una tabla](#165-búsqueda-de-un-elemento-en-una-tabla) - [16.6 Ordenación de las tablas](#166-ordenación-de-las-tablas) - [16.6.1 Inserción ordenada](#1661-inserción-ordenada) - [16.6.2 Algoritmo de ordenación](#1662-algoritmo-de-ordenación) - [16.6.3 Importancia del orden en las tablas](#1663-importancia-del-orden-en-las-tablas) - [16.6.3.1 Ejemplo](#16631-ejemplo) - [16.7 Tabla de tipos estructurados](#167-tabla-de-tipos-estructurados) - [16.7.1 Tablas de tuplas](#1671-tablas-de-tuplas) - [16.7.2 Tabla de tablas](#1672-tabla-de-tablas) - [16.8 Ejercicios](#168-ejercicios) ## 16. Tipos de datos estructurados: tabla Una tabla es un tipo de dato estructurado que permite almacenar un conjunto de elementos del mismo tipo. Cada elemento de la tabla se identifica mediante un índice que indica su posición en la tabla. El índice de un elemento de una tabla es un número entero que va desde 1 hasta el número de elementos de la tabla. En la mayoría de los lenguajes de programación, el índice de un elemento de una tabla se inicia en 1. En algunos lenguajes de programación, como C, el índice de un elemento de una tabla se inicia en 0. ## 16.1 Sintaxis para la declaración (definición) de tablas Los elementos que se necesitan para declarar una tabla son: - Un vector que define la longitud de la tabla y el tipo de elemento que se guardará. Por ejem: - Predefinidos en el lenguaje algotítmico (integer, real, char, boolean) - Tipos estructurados definidos por el usuario - Una variable de tipo entero que se utiliza para indicar el número de elementos que hay en cada momento en la tabla (La ocupación de la tabla). La declaración que hacemos es la de un tipo estructurado (tupla) que después podemos utilizar para definir variables dentro del algoritmo. ```alg {constant definition - where length is a constant that defines the length of the vector} const MAX_ELEMENTS: integer = length; end const {type definition} type tExampleTable = record elements: vector[MAX_ELEMENTS] of integer; numElements: integer; end record end type {var definition using the type} var aTable: tExampleTable; end var ``` ```c #include #define MAX_ELEMENTS length typedef struct { int elements[MAX_ELEMENTS]; int numElements; } tExampleTable; tExampleTable aTable; ``` ### 16.1.1 Ejemplo Guardar un cuadro de control para las puertas de un edificio de un complejo de edificios. Cada elemento de la tabla indica si la puerta correspondiente está abierta o cerrada. Cada edificio tiene como máximo 40 puertas: ```alg const MAX_GATES: integer = 40; end const type tGates = record stateGates: vector[MAX_GATES] of boolean; numGates: integer; end record end type var bulding1: tGates; bulding2: tGates; end var ``` ```c #include #include #define MAX_GATES 40 typedef struct { bool stateGates[MAX_GATES]; int numGates; } tGates; tGates bulding1; tGates bulding2; ``` ### 16.1.2 Acceso a los elementos de una tabla Podemos acceder a los diferentes elementos de una tabla de manera similar a como lo hacíamos con los vectores, pero teniendo en cuenta que se trata de una tupla. ```alg const K: integer = 10; MAX_GATES: integer = 40; end const type tGates = record stateGates: vector[MAX_GATES] of boolean; numGates: integer; end record end type {header of fillTable} action fillTable (out Building: tGates); algorithm checkDoors var building1: tGates; building2: tGates; p: integer; b: boolean; c: boolean; end var c := true; fillTable(building1); {the following statements treat the element of the table as variables} {assigns the third element of the table building1 to the variable b} b:= building1.stateGates[3]; {assigns the value of the variable c to the Kth gate of building1, assuming that K is a constant such that 1 ≤ K≤ 40} building1.stateGates[K]:= c; {assigns the value of the first gate of building1 to the gate 2*p +5 as long as 1 ≤ 2*p+5 ≤ 40} building1.stateGates[2*p+5]:= building1.stateGates[1]; end algorithm ``` ```c #include #include #define K 10 #define MAX_GATES 40 typedef struct { bool stateGates[MAX_GATES]; int numGates; } tGates; void fillTable (tGates *Building); int main(int argc, char** argv) { tGates building1; tGates building2; int p; bool b; bool c = true; /* the following statements treat the elements of the table as variables */ fillTable(&building1); /* assigns the third element of the table building1 to the variable b */ b = building1.stateGates[2]; /* assigns the value of the variable c to the kth gate of building1, assuming that k is a constant such that 1 ≤ K ≤ 40 */ building1.stateGates[K-1] = c; /* assigns the value of the first gate of building1 to the gate 2*p +5 as long as 1 ≤ 2*p+5 ≤ 40 */ building1.stateGates[2*p+5-1] = building1.stateGates[0]; return 0; } ``` Comentarios: - En el lenguaje algorítmico las tablas se indexan empezando con el número 1 mientras en C se indexan a partir del 0. - Algunos lenguajes de programación permiten indexar con culquier rango, por ejemplo, del 10 al 60. - Durante la ejecución es importante controlar que el índice siempe esté dentro de los límites esperados para evitar errores. ### 16.1.3 Ejemplo Una empresa con diversos cines de tipo multisala. Sabemos que el cine más grande tiene 20 salas. Creamos una tabla para guardar la recaudación de cada sala pero que sirva para cualquiera de los cines. Es decir, definimos una tabla que pueda guardar hasta 20 importes reales. La tabla no siempre se llemará ya que dependerá del número de salas que tenga cada cine. ```alg const MAX_THEATERS: integer = 20; end const type tTheaters = record collect: vector[MAX_THEATERS] of real; numTheaters: integer; end record end type var santalo: tTheaters; sants: tTheaters; end var ``` ```c #include /* Definition of a constant to indicate the size of the table */ #define MAX_THEATERS 20 typedef struct { float collect[MAX_THEATERS]; int numTheaters; } tTheaters; /*var declaration assuming two movies */ tTheaters santalo; tTheaters sants; ``` ## 16.2 Inicialización de una tabla Las variables de tipo tabla, como todas las variables, deben inicializarse antes de ser utilizadas. En el caso de las tablas, la manera de inicializarlas es indicando que está vacía. Lo hacemos asignando 0 al número de elementos ocupados en la tabla. Volviendo al anterior ejemplo, si queremos indicar que los cines inicialmente no tienen ninguna recaudación, debemos hacer lo siguiente: ```alg const MAX_THEATERS: integer = 20; end const type tTheaters = record collect: vector[MAX_THEATERS] of real; numTheaters: integer; end record end type algorithm initTheaters var santalo: tTheaters; sants: tTheaters; end var {table initialitation, setting the number of theater to 0} santalo.numTheaters := 0; sants.numTheaters := 0; end algorithm ``` ```c #include #define MAX_THEATERS 20 typedef struct { float collect[MAX_THEATERS]; int numTheaters; } tTheaters; /var declaration */ tTheaters santalo; tTheaters sants; int main(int argc, char** argv) { /* table initialitation, setting the number of theater to 0 */ santalo.numTheaters = 0; sants.numTheaters = 0; return 0; } ``` ## 16.3 Carga de datos a partir de una secuencia Una operación habitual es carga la tabla con información recogida en el canal estándar de entrada. Los datos vienen dados con una serie de reales (una secuencia de reales) que leemos del canal estándar y el valor -1.0 indica que es el final de los datos (fin de la secuencia de entrada). Continuamos con el ejemplo anterior y, para una mejor estructura, aislamos la lectura de la información en un acción. ```alg const MAX_THEATERS: integer = 20; END_SEQ: real = -1.0; end const type tTheater = record collect: vector[MAX_THEATERS] of real; numTheaters: integer; end record end type action fillTable(out movieTheater: tTheater); var temp: real; end var {table initialization} movieTheater.numTheaters:=0; temp:= readReal(); {we read the first number} {iteration while the read number is not -1} while temp ≠ END_SEQ do {Save the read number in the table.} movieTheater.collect[movieTheater.numTheaters+1]:= temp; movieTheater.numTheaters:= movieTheater.numTheaters + 1; temp:= readReal(); end while end action ``` ```c #include #define END_SEQ -1.0 #define MAX_THEATERS 20 typedef struct { float collect[MAX_THEATERS]; int numTheaters; } tTheater; void fillTable(tTheater *movieTheater) { /* var definition */ float temp; /* table initialization */ movieTheater->numTheaters = 0; scanf("%f", &temp); /* we read the first number */ /* iteration while the read number is not -1 */ while (temp != END_SEQ) { /* Save the read number in the table. */ movieTheater->collect[movieTheater->numTheaters] = temp; movieTheater->numTheaters = movieTheater->numTheaters + 1; temp = readReal(); } } ``` Comentarios: - Cada elemento de la tabla se trata como una variable. - Antes de entrar en la iteración se lee el primer elemento. Así, antes de entrar en el bucle ya se puede comprobar si el valor del elemento es el final de la secuencia o no. - En cada iteración incrementamos el valor de `numTheaters` para indicar que hay un elemento más en la tabla. - A la acción le pasamos un valor de entrada/salida de tipo tabla. La acción modifica el valor de la tabla con los datos introducidos. - En el lenguaje algorítmico el índice empieza en 1 mientras que en C empieza en 0. - Cuando se pasa una estructura como parámetro de entrada/salida para acceder a los campos de la tupla (record) en lenguaje algorítmico se usa el punto (.) y en C se usa la notación ->. ## 16.4 Recorrido de una tabla Para recorrer una tabla se puede hacer de dos maneras: - Recorrido secuencial: se recorren todos los elementos de la tabla uno a uno. - Recorrido por búsqueda: se busca un elemento en la tabla y se recorre a partir de él. Siguiendo con el ejemplo anterior, vamos a realizar la simulación de un aumento del precio al 20%. Con lo cuál, vamos a aislar en una acción la operación de recorrer la tabla para multiplicar cada uno de sus elementos por 1.2. ```alg const MAX_THEATERS: integer = 20; END_SEQ: real = -1.0; end const type tTheater = record collect: vector[MAX_THEATERS] of real; numTheaters: integer; end record end type action update(inout movieTheater: tTheater); var i: integer; end var {iteration. We can use a for ... do iteration because we know the exact number of element of the table} for i:= 1 to movieTheater.numTheaters do movieTheater.collect[i]:= movieTheater.collect[i]*1.2; end for end action ``` ```c #include #define END_SEQ -1.0 #define MAX_THEATERS 20 typedef struct { float collect[MAX_THEATERS]; int numTheaters; } tTheater; void update(tTheater *movieTheater) { /* var definition */ int i; /* iteration. We can use a for ... do iteration because we know the exact number of element of the table */ for (i = 0; i < movieTheater->numTheaters; i++) { movieTheater->collect[i] = movieTheater->collect[i] * 1.2; } } ``` Comentarios: - Para realizar el recorrido completo, podemos hacerlo utilizando el for ... do para iterar sobre todos los elementos de la tabla ya que sabemos exactamente cuántos elementos hay presentes. - En C la iteración se hace de 0 a `movieTheater.numTheaters - 1` ya que el índice de la tabla empieza en 0 y en lenguaje algorítmico empieza en 1. ### 16.4.1 Ejemplo: lectura y recurrido Ahora vamos a realizar un algoritmo que lea del canal estándar la secuencia con la recaudación de las salas del cine, la muestre por el canal estándar, calcule el porcentaje indicado de sus elementos y la vuelva a mostrar por el canal estándar de salida. Usaremos una acción para mostrar el contenido de la tabla: ```alg const MAX_THEATERS: integer = 20; END_SEQ: real = -1.0; end const type tTheater = record collect: vector[MAX_THEATERS] of real; numTheaters: integer; end record end type algorithm simulation var santalo: tTheater; end var fillTable(santalo); printTable(santalo); update(santalo); printTable(santalo); end algorithm action fillTable(out movieTheater: tTheater); var temp: real; end var {table initialization} movieTheater.numTheaters:=0; temp:= readReal(); {we read the first number} {iteration while the read number is not -1} while temp ≠ END_SEQ do {Save the read number in the table} movieTheater.numTheaters:=movieTheater.numTheaters + 1; movieTheater.collect[movieTheater.numTheaters]:= temp; temp:= readReal(); end while end action action update(inout movieTheater: tTheater) var i: integer; end var {iteration. We can use a for ... do iteration because we know the exact number of element of the table} for i:=1 to movieTheater.numTheaters do movieTheater.collect[i]:= movieTheater.collect[i] * 1.20; end for end action action printTable(in movieTheater: tTheater) var i: integer; end var {iteration. We can use a for ... do iteration because we know the exact number of element of the table} for i:=1 to movieTheater.numTheaters do writeReal(movieTheater.collect[i]); end for end action ``` ```c #include #define END_SEQ -1.0 #define MAX_THEATERS 20 typedef struct { float collect[MAX_THEATERS]; int numTheaters; } tTheater; void fillTable(tTheater *movieTheater) { /* var definition */ float temp; /* table initialization */ movieTheater->numTheaters = 0; scanf("%f", &temp); /* we read the first number */ /* iteration while the read number is not -1 */ while (temp != END_SEQ) { /* Save the read number in the table */ movieTheater->collect[movieTheater->numTheaters] = temp; movieTheater->numTheaters = movieTheater->numTheaters + 1; scanf("%f", &temp); } } void update(tTheater *movieTheater) { /* var definition */ int i; /* iteration. We can use a for ... do iteration because we know the exact number of element of the table */ for (i = 0; i < movieTheater->numTheaters; i++) { movieTheater->collect[i] = movieTheater->collect[i] *1.20 ; } } void printTable(tTheater movieTheater) { /* var definition */ int i; /* iteration. We can use a for ... do iteration because we know the exact number of element of the table */ for (i=0; i< movieTheater.numTheaters; i++) { printf("%f ", movieTheater.collect[i]); } } int main(int argc, char** argv) { tTheater santalo; fillTable(&santalo); printTable(santalo); update(&santalo); printTable(santalo); return 0; } ``` Comentarios: - Hemos escrito un algoritmo completo que hemos estructurado con acciones donde cada acción hace una operación concreta sobre una tabla de valores de tipo real. - Las acciones incluyen la inserción de elementos en la tabla y el control de cuántos se han insertado, un recorrido para aumentar la recaudación y otro recorrido para mostrar por el canal estándar los valores guardados en la tabla. - En la acción de escritura, la tabla se pasa como parámetro solamente de entrada. Fijaos en que en C, en este caso, la notación utilizada para acceder a los campos de la tupla (record) es el punto (.). ## 16.5 Búsqueda de un elemento en una tabla Para realizar una búsqueda debemos hacer un recorrido de todos los elementos de la tabla, pero a diferencia del recorrido secuencial, en este caso, paramos cuando encontramos el elemento que buscamos. Por lo tanto la iteración debe ser con un bucle while y no con un for. ```alg const MAX_THEATERS: integer = 20; END_SEQ: real = -1.0; end const type tTheater = record collect: vector[MAX_THEATERS] of real; numTheaters: integer; end record end type algorithm simulation var movieTheater: tTheater; value: real; position: integer; end var fillTable(movieTheater); value:= readReal(); searchValue(movieTheater, value, position); writeInteger(position); end algorithm action fillTable(out movieTheater: tTheater); var i: integer; temp: real; end var {table initialization} movieTheater.numTheaters:=0; temp:= readReal(); {we read the first digit} {iteration while the read number is not -1} while temp ≠ END_SEQ do {Save the read number in the table} movieTheater.numTheaters:=movieTheater.numTheaters + 1; movieTheater.collect[movieTheater.numTheaters]:= temp; temp:= readReal(); end while end action action searchValue(in movieTheater: tTheater, in value: real, out position: integer) var i: integer; found: boolean; end var {variable initialization. i is set to 1 to start searching in the table at postion 1 and found to false to indicate that so far value has not been found. The out parameter position is set to -1 by default} i:= 1; found:= false; position:= -1; {iteration while there still are elements in the table and the value has not been found} while i≤ movieTheater.numTheaters and not found do if movieTheater.collect[i] ≥ value then found:= true; else i:=i + 1; end if end while if found then position := i; end if end action ``` ```c #include #include #define END_SEQ -1.0 #define MAX_THEATERS 20 typedef struct { float collect[MAX_THEATERS]; int numTheaters; } tTheater; void fillTable(tTheater *movieTheater) { /* var definition */ float temp; /* table initialization */ movieTheater->numTheaters = 0; scanf("%f", &temp); /* read the first digit */ /* iteration while the read number is not -1 */ while (temp != END_SEQ) { /* Save the read number in the table */ movieTheater->collect[movieTheater->numTheaters] = temp; movieTheater->numTheaters = movieTheater->numTheaters + 1; scanf("%f", &temp); } } void searchValue(tTheater movieTheater, float value, int *position) { /* var definition */ int i; bool found; /* variable initialization. i is set to 0 to start searching in the table at postion 0 and found to false to indicate that so far value has not been found. The out parameter position is set to -1 by default */ i = 0; found = false; *position = -1; /* iteration while there still are elements in the table and the value has not been found */ while (i < movieTheater.numTheaters && !found) { if (movieTheater.collect[i] >= value) { found = true; } else { i++; } } if (found) { *position = i; } } int main(int argc, char** argv) { tTheater movieTheater; float value; int position; fillTable(&movieTheater); printf("%d", movieTheater.numTheaters); scanf("%f", &value); searchValue(movieTheater, value, &position); printf("%d", position); return 0; } ``` Comentarios: - Se inicializa el valor de la variable `position` a -1 para indicar que no se ha encontrado el valor buscado. - Para buscar el elemento iteramos con el bucle while controlando si se encuentra el valor o no. Si se encuentra no llega al final de la tabla. No podemos usar un for ya que no sabemos en qué momento podemos encontrar el valor buscado. - En el lenguaje algorítmico el índice empieza en 1 mientras que en C empieza en 0. - El parámetro `position` es de salida, por eso se utiliza el caracter * delante del nombre del parámetro. ## 16.6 Ordenación de las tablas ### 16.6.1 Inserción ordenada Vamos a modificar en el ejemplo anterior la acción de lectura de las recaudaciones para que se mantenga la tabla siempre ordenada. ```alg const MAX_THEATERS: integer = 20; END_SEQ: real = -1.0; end const type tTheater = record collect: vector[MAX_THEATERS] of real; numTheaters: integer; end record end type action fillTable(out movieTheater: tTheater); var i, j: integer; found: boolean; temp: real; end var {table initialization} movieTheater.numTheaters:=0; temp:= readReal(); {we read the first digit} {iteration while the read number is not -1} while temp ≠ END_SEQ do {find the right location} i:= 1; found:= false; {search for the right location} while i ≤ movieTheater.numTheaters and not found do if movieTheater.collect[i] ≥ temp then found:= true; else i:= i + 1; end if end while {all the values to the right of the position found must be moved to one position to the right} if movieTheaters.numTheathers > 0 then for j:= movieTheaters.numTheathers to i step -1 do movieTheater.collect[j+1]:= movieTheater.collect[j]; end for end if {insert new value} movieTheater.collect[i]:= temp; movieTheater.numTheaters:= movieTheater.numTheaters + 1; temp:= readReal(); end while end action ``` ```c #include #include #define END_SEQ -1.0 #define MAX_THEATERS 20 typedef struct { float collect[MAX_THEATERS]; int numTheaters; } tTheater; void fillTable(tTheater *movieTheater) { /* var definition */ float temp; int i, j; bool found; /* table initialization */ movieTheater->numTheaters = 0; scanf("%f", &temp); /* read the first digit */ /* iteration while the read number is not -1 */ while (temp != END_SEQ) { i = 0; found = false; /* search for the right location */ while (i < movieTheater->numTheaters && !found) { if (movieTheater->collect[i] >= temp) { found = true; } else { i++; } } /* move values to the right */ if (movieTheater->numTheaters > 0) { for (j = movieTheater->numTheaters; j >= i; j--) { movieTheater->collect[j] = movieTheater->collect[j-1]; } } /* insert new value */ movieTheater->collect[i] = temp; movieTheater->numTheaters = movieTheater->numTheaters + 1; scanf("%f", &temp); } } int main(int argc, char** argv) { tTheater santalo; int i; fillTable(&santalo); for (i = 0; i < santalo.numTheaters; i++) { printf("%f ", santalo.collect[i]); } return 0; } ``` Comentarios: - Para mantener la tabla ordenada cada vez que se inserte un valor nuevo, primnero es necesario buscar el lugar adecuado que le corresponde según los valores que ya hay en la tabla y el que queremos insertar. Para encontrarlo usamos una búsqueda, que corresponde al while más interno. - Una vez encontrado el sitio correcto, es necesario desplazar hacia la derecha 1 casilla todos los elementos que quedan a la derecha del punto donde se debe insertar. Para hacerlo, usamos una iteración de tipo for, ya que savemos cuántos elementos se debe mover. - En el algoritmo hemos uspuesto que en la secuencia de entrada nunca habrá más números de los permitidos. Si no se sabe con seguridad, sería necesario añadir al algoritmo un control para evitar que se intente insertar un elemento fuera del rango de la tabla. ### 16.6.2 Algoritmo de ordenación La ordenación de las tablas es un tema bastante extenso, vamos a ver uno fácil de entender, aunque no sea el más eficiente. Si la tabla tiene n elementos, el algoritmo consiste en iterar n veces de la siguiente manera: 1. La primera iteración es un recorrido por toda la tabla para encontrar el elemento menor. Cunado se identifica, se intercambian los elementos de la posición 1 y la posición del más pequeño, de tal manera que al acabar la primera iteración sabemos que el primer elemento de la tabla es el menor. 2. En la segunda iteración ya no hace falta recorrer toda la tabla, sino que podemos empezar en el segundo elemento y hacer el mismo proceso pero desde la posición 2. 3. En la tercer iteración se repite el procedimiento pero empezando en la posición 3. 4. Y así se repite el procedimiento hasta la última iteración. Ahora vamos a retomar el ejemplo anterior y rellenamos la tabla con las recaudaciones usando el algoritmo inicial y ordenando como la anterior metodología. ```alg const MAX_THEATERS: integer = 20; END_SEQ: real = -1.0; end const type tTheater = record collect: vector[MAX_THEATERS] of real; numTheaters: integer; end record end type algorithm simulation var santalo: tTheater; end var fillTable(santalo); sort(santalo); for i:= 1 to santalo.numTheaters do writeReal(santalo.collect[i]); end for end algorithm action fillTable(out movieTheater: tTheater); var i: integer; temp: real; end var {table initialization} movieTheater.numTheaters:=0; temp:= readReal(); {we read the first digit} {iteration while the read number is not -1} while temp ≠ END_SEQ do {Save the read number in the table} movieTheater.numTheaters:=movieTheater.numTheaters + 1; movieTheater.collect[movieTheater.numTheaters]:= temp; temp:= readReal(); end while end action action sort(inout movieTHeater:tTheater) var i, j, posMin: integer; aux: integer; end var i:= 1; while j ≤ movieTheater.numTheaters do posMin:= i; j:= i + 1; while j ≤ movieTheater.numTheaters do if movieTheater.collect[j] < movieTheater.collect[posMin] then posMin:= j; end if j:= j + 1; end while aux:= movieTheater.collect[posMin]; movieTheater.collect[posMin]:= movieTheater.collect[i]; movieTheater.collect[i]:= aux; i:= i + 1; end while end action ``` ```c #include #define END_SEQ -1.0 #define MAX_THEATERS 20 typedef struct { float collect[MAX_THEATERS]; int numTheaters; } tTheater; void fillTable(tTheater *movieTheater) { /* var definition */ int i; float temp; /* table initialization */ movieTheater->numTheaters = 0; scanf("%f", &temp); /* read the first digit */ /* iteration while the read number is not -1 */ while (temp != END_SEQ) { /* Save the read number in the table */ movieTheater->collect[movieTheater->numTheaters] = temp; movieTheater->numTheaters = movieTheater->numTheaters + 1; scanf("%f", &temp); } } void sort(tTheater *movieTheater) { /* var definition */ int i, j, posMin; float aux; i = 0; while (i < movieTheater->numTheaters) { posMin = i; j = i + 1; while (j < movieTheater->numTheaters) { if (movieTheater->collect[j] < movieTheater->collect[posMin]) { posMin = j; } j++; } aux = movieTheater->collect[posMin]; movieTheater->collect[posMin] = movieTheater->collect[i]; movieTheater->collect[i] = aux; i++; } } int main(int argc, char** argv) { tTheater santalo; int i; fillTable(&santalo); sort(&santalo); for (i = 0; i < santalo.numTheaters; i++) { printf("%f ", santalo.collect[i]); } return 0; } ``` ### 16.6.3 Importancia del orden en las tablas Si analizamos el anterior algoritmo de búsqueda, podemos ver que, en el peor de los casos, cuando el elemento buscado no se encuentra en la tabla se debe recorrer la tabla entera. Es una búsqueda de orden lineal, es decir, recorre todos los elementos. Hay maneras más óptimas de buscar elementos dentro de una tabla, pero requieren que la tabla esté ordenada, cosa que podemos obtener o bien insertando los elementos en orden o bien ordenando la tabla posteriormente. Con una tabla ordenada se puede plantear otra forma, no empezando en la primera posición sino empezando por el medio: 1. Calculamos la posición que está en el medio. 2. Comparamos su contenido con el valor buscado. 3. Si el contenido es el valor buscado, hemos terminado. Si no, hacemos los siguiente 1. Si el elemento del medio es mayor podemos descartar la segunda mitad de la tabla y buscamos en la primera mitad. 2. En caso contrario, pues viceversa. 4. Aplicamos el mismo procedimiento pero trabajando con la mitad de la tabal que no hemos descartado. #### 16.6.3.1 Ejemplo Siguiendo el ejemplo de los cines, sunpogamos que queremos buscar si ha habido alguna sala con una recaudación de 100€, suponiendo que la tabla está ordenada. ```alg const MAX_THEATERS: integer = 20; end const type tTheater = record collect: vector[MAX_THEATERS] of real; numTheaters: integer; end record end type action searchValue(in movieTheater: tTheater, in value: real, out position: integer) var i: integer; first, last, middle: integer; end var first:= 1; position:= -1; last:= movieTheater.numTheaters; while (first≠last) do middle:= (first + last) div 2; if movieTheater.collect[middle] < value then first:= middle + 1; else last:= middle - 1; end if end while if movieTheater.collect[first] = value then position:= first; end if end action ``` ```c #include /* type definition for a table of 20 elements */ #define MAX_THEATERS 20 typedef struct { float collect[MAX_THEATERS]; int numTheaters; } tTheater; void searchValue(tTheater movieTheater, float value, int *position) { /* var definition */ int i; int first, last, middle; first = 0; *position = -1; last = movieTheater.numTheaters-1; while (first != last) { middle = (first + last) / 2; if (movieTheater.collect[middle] < value) { first = middle + 1; } else { last = middle; } } if (movieTheater.collect[first] == value) { *position = first; } } ``` ## 16.7 Tabla de tipos estructurados ### 16.7.1 Tablas de tuplas Las tablas pueden ser de cualquier tipo de datos, ya sean tipos básicos del lenguaje de programación o tipos estructurados definidos por el usuario. Siguiendo con el ejemplo de los cines, vamos a suponer que, además de la recaudación, queremos guardar más información de cada sala. Tal y como trabajabamos hasta ahora se podía suponer que la posición 1 correspondía a la sala 1, la posición 2 a la sala 2, etc. Pero cuando hemos ordenado los importes hemos perdido está información. Podemos definir una tupla con la información de cada sala, por ejemplo, que tenga un entero para la capacidad de la sala, una cadena de caracteres para identificar el nombre de la sala, un real para la recaudación y la fecha de la recaudación. De esta forma, si movemos los elementos de la tabla no perderemos información. ```alg const MAX_THEATERS: integer = 20; end const type {declaration of a type for dates} tDate = record day: integer; month: integer; year: integer; end record; {declaration of type for theater information} tTheaterDescription = record name: string; capaciy:integer; collect: real; date: tDate end record; {table with the information of each theater} tTheater = record movieTheaters: vector[MAX_THEATERS] of tTheaterDescription; numTheaters: integer; end record; end type algorithm movieTheater var santalo: tTheater; k: integer; end var {we can access the information in the folowing way} {to access to the name of the third theater in santalo} santalo.movieTheaters[3].name; {to access to the filed collect of the k th theater in santalo} santalo.movieTheaters[k].collect; {to access to the capacity of the last theater stored in the table santalo} santalo.movieTheaters[santalo.numTheaters].capacity; end algorithm ``` ```c #include #define MAX_THEATERS 20 #define MAX_NAME 50 typedef struct { int day; int month; int year; } tDate; typedef struct { char name[MAX_NAME]; int capacity; float collect; tDate date; } tTheaterDescription; typedef struct { tTheaterDescription movieTheaters[MAX_THEATERS]; int numTheaters; } tTheater; int main(int argc, char** argv) { tTheater santalo; int k; /* we can access the information in the folowing way */ /* to access to the name of the third theater in santalo */ santalo.movieTheaters[2].name; /* to access to the filed collect of the k th theater in santalo */ santalo.movieTheaters[k-1].collect; /* to access to the capacity of the last theater stored in the table santalo */ santalo.movieTheaters[santalo.numTheaters-1].capacity; return 0; } ``` Comentarios: - Podemos ver que se ha definido una tabla igual que antes, pero ahora cada elemento es una estructura con varios campos. - Con una variable del tipo tTheater podemos acceder a toda la información siguiendo la misma notación que para las tablas y las tuplas. ### 16.7.2 Tabla de tablas En este caso vamos a definir otro tipo estructurado. Para facilitar el uso vamos a mantener la información de todos los cines en una única variable. Definimos una tabla donde cada elemento sea una tabla con la recaudación de las salas de cada cine. ```alg const MAX_THEATERS: integer = 20; MAX_MOVIES: integer = 15; end const type {declaration of a type for dates} tDate = record day: integer; month: integer; year: integer; end record; {declaration of type for theater information} tTheaterDescription = record name: string; capacity: integer; collect: real; date: tDate; end record; {table with the information of each theater} tTheater = record movieTheaters: vector[MAX_THEATERS] of tTheaterDescription; numTheaters: integer; end record; {declaration of a table of tTheater} tCompany = record movies: vector[MAX_MOVIES] of tTheater; numMovies: integer; end record; end type algorithm movieTheater var theMovieCompany: tCompany; m, k: integer; end var {we can access the information in the folowing way} {to access to the name of the third theater of the first movie} theMovieCompany.movies[1].movieTheaters[3].name; {to access to the field collect of the k th theater of the m th movie} theMovieCompany.movies[m].movieTheaters[k].collect; {to access to the capacity of the last theater of the last movie} theMovieCompany.movies[theMovieCompany.numMovies].movieTheaters[theMovieCompany.movies[theMovieCompany.numMovies].numTheaters].capacity; end algorithm ``` ```c #include #define MAX_THEATERS 20 #define MAX_MOVIES 15 typedef struct { int day; int month; int year; } tDate; typedef struct { tString name; int capacity; float collect; tDate date; } tTheaterDescription; typedef struct { tTheaterDescription movieTheaters[MAX_THEATERS]; int numTheaters; } tTheater; /* declaration of a table of tTheater */ typedef struct { tTheater movies[MAX_MOVIES]; int numMovies; } tCompany; int main(int argc, char** argv) { tCompany theMovieCompany; int m, k; /* we can access the information in the folowing way */ /* to access to the name of the third theater of the first movie */ theMovieCompany.movies[0].movieTheaters[2].name; /* to access to the field collect of the k th theater of the m th movie */ theMovieCompany.movies[m-1].movieTheaters[k-1].collect; /* to access to the capacity of the last theater of the last movie */ theMovieCompany.movies[theMovieCompany.numMovies-1].movieTheaters[theMovieCompany.movies[theMovieCompany.numMovies-1].numTheaters-1].capacity; return 0; } ``` ## 16.8 Ejercicios - **Ejercicio 1**: Dada una tabla de reales, implementa un algoritmo que calcule la media de los valores de la tabla. - **Ejercicio 2**: Dada una tabla de reales, implementa un algoritmo que calcule el valor máximo de la tabla. - **Ejercicio 3**: Dada una tabla de reales, implementa un algoritmo que calcule el valor mínimo de la tabla. - **Ejercicio 4**: Dada una tabla de reales, implementa un algoritmo que calcule la suma de los valores de la tabla. Tabla de reales: ``` 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 -1.0 ``` Soluciones: - **Ejercicio 1**: ```alg type tReal = record collect: vector[10] of real; position: integer; end record end type action mediaValores(in tabla: tReal) var suma: real; i: integer; end var suma:= 0; for i:= 1 to tabla.position do suma:= suma + tabla.collect[i]; end for writeReal(suma / tabla.position); end action algorithm simulation var tabla: tReal; end var tabla.collect[1]:= 1.0; tabla.collect[2]:= 2.0; tabla.collect[3]:= 3.0; tabla.collect[4]:= 4.0; tabla.collect[5]:= 5.0; tabla.collect[6]:= 6.0; tabla.collect[7]:= 7.0; tabla.collect[8]:= 8.0; tabla.collect[9]:= 9.0; tabla.collect[10]:= 10.0; tabla.position:= 10; mediaValores(tabla); end algorithm ``` [Solución en c](./soluciones_c/solucion1/media.c) - **Ejercicio 2**: ```alg type tReal = record collect: vector[10] of real; position: integer; end record end type action maxValores(in tabla: tReal) var max: real; i: integer; end var max:= tabla.collect[1]; for i:= 2 to tabla.position do if tabla.collect[i] > max then max:= tabla.collect[i]; end if end for writeReal(max); end action algorithm simulation var tabla: tReal; end var tabla.collect[1]:= 1.0; tabla.collect[2]:= 2.0; tabla.collect[3]:= 3.0; tabla.collect[4]:= 4.0; tabla.collect[5]:= 5.0; tabla.collect[6]:= 6.0; tabla.collect[7]:= 7.0; tabla.collect[8]:= 8.0; tabla.collect[9]:= 9.0; tabla.collect[10]:= 10.0; tabla.position:= 10; maxValores(tabla); end algorithm ``` [Solución en c](./soluciones_c/solucion2/max.c) - **Ejercicio 3**: ```alg type tReal = record collect: vector[10] of real; position: integer; end record end type action minValores(in tabla: tReal) var min: real; i: integer; end var min:= tabla.collect[1]; for i:= 2 to tabla.position do if tabla.collect[i] < min then min:= tabla.collect[i]; end if end for writeReal(min); end action algorithm simulation var tabla: tReal; end var tabla.collect[1]:= 1.0; tabla.collect[2]:= 2.0; tabla.collect[3]:= 3.0; tabla.collect[4]:= 4.0; tabla.collect[5]:= 5.0; tabla.collect[6]:= 6.0; tabla.collect[7]:= 7.0; tabla.collect[8]:= 8.0; tabla.collect[9]:= 9.0; tabla.collect[10]:= 10.0; tabla.position:= 10; minValores(tabla); end algorithm ``` [Solución en c](./soluciones_c/solucion3/min.c) - **Ejercicio 4**: ```alg type tReal = record collect: vector[10] of real; position: integer; end record end type action sumaValores(in tabla: tReal) var suma: real; i: integer; end var suma:= 0; for i:= 1 to tabla.position do suma:= suma + tabla.collect[i]; end for writeReal(suma); end action algorithm simulation var tabla: tReal; end var tabla.collect[1]:= 1.0; tabla.collect[2]:= 2.0; tabla.collect[3]:= 3.0; tabla.collect[4]:= 4.0; tabla.collect[5]:= 5.0; tabla.collect[6]:= 6.0; tabla.collect[7]:= 7.0; tabla.collect[8]:= 8.0; tabla.collect[9]:= 9.0; tabla.collect[10]:= 10.0; tabla.position:= 10; sumaValores(tabla); end algorithm ``` [Solución en c](./soluciones_c/solucion4/suma.c) [Volver arriba](#pr-1)