TEMA 5. Tratamientos secuenciales

Anuncio
Autor: José C. Riquelme (Universidad de Sevilla)
TEMA 5. Tratamientos secuenciales
1. Introducción
Es habitual que en numerosos cursos de programación universitarios en titulaciones de
Ingeniería se aprenda a resolver determinados problemas sin ninguna metodología
específica, sino siguiendo la técnica de “prueba y error”. Esto es, se escribe una
aproximación al algoritmo solución y después se va depurando hasta conseguir la
solución al problema. En estos cursos se plantean a los alumnos diferentes problemas
que se solucionan todos de forma distinta cuando muchos de ellos tienen una solución
común. Esta forma de enseñar a programar es la que confiere a la programación ese
(nefasto) matiz de “arte”, en el sentido de que hacer un programa se parece a estar
pintando un cuadro y se van dando pinceladas aquí y allá hasta que el resultado guste.
En esos (malos) cursos se incide demasiado en la solución específica de un problema
determinado, sin dar al alumno una visión ingenieril de la programación. En este
manual se va a intentar agrupar un conjunto de problemas que son muy comunes en
programación y cuya solución presenta las suficientes similitudes como para conseguir
una solución sistemática para ellos.
Supongamos tenemos una colección de datos que pueden ser de muy diversos tipos: los
empleados de una empresa, los alumnos de un curso, los pacientes de un hospital, las
ventas de unos grandes almacenes, los productos de un almacén, los resultados de un
experimento biológico, los vuelos de un aeropuerto, los resultados de una encuesta
electoral… Todos estos datos estarán formados preferentemente por valores numéricos
(enteros o reales) y cadenas de caracteres almacenados en arrays (de una o dos
dimensiones). Por ejemplo, el dni o el sueldo de un empleado, las notas de los alumnos,
la edad de los pacientes, el código de una venta, el precio de un producto, el pH de un
tejido, la hora de salida de un avión, el número de votantes a un partido…
¿Cuáles son las preguntas típicas que se pueden consultar sobre este tipo de datos?
Pongamos algunos ejemplos:







¿Cuánto vale la suma de todas las nominas de la empresa de mayores de 50
años?
¿Cuántos alumnos han aprobado todas las asignaturas?
¿Ha habido alguna venta superior a 1000 euros hoy?
¿Cuál es el producto con mayor stock en el almacén?
¿Cuál es el próximo avión con plazas libres y destino Madrid?
¿Todos los tejidos superan un pH de cuatro?
¿Cuál es el partido mayoritario entre los mayores de 60 años?
En general, estas preguntas se pueden simplificar en las siguientes:
 Sumar o acumular
 Contar
Tema 5. Tratamientos secuenciales




Existe algún elemento
Todos los elementos cumplen
Hallar el máximo
Hallar el mínimo
¿Es posible que todas estas preguntas tengan una base común para su solución
algorítmica? La respuesta es sí.
2. Esquemas algorítmicos básicos
Todos los problemas sobre colecciones deben hacer un recorrido sobre la misma
mediante un bucle. Por otro lado, si no se requiere realizar el cálculo sobre toda la
colección se deben filtrar los elementos que intervienen mediante una bifurcación. Por
tanto, el esquema general debe ser:
Para todo elemento de la colección
Si el elemento cumple la propiedad
Realizar cálculo sobre elemento
Todas las preguntas se responden mediante la actualización de una variable que
almacena los resultados intermedios al recorrer la colección. Por ejemplo, si estamos
hallando una suma, la suma parcial hasta el elemento que estamos tratando, el contador
parcial, el máximo hasta ese momento, etc. Dependiendo de la pregunta que se responda
el tipo y la inicialización de la variable será diferente. Por ejemplo, si la pregunta es
hallar la suma de valores reales, el tipo será numérico real y la inicialización a cero, si
es un contador será de tipo entero y también inicializada a cero, si es un máximo o
mínimo será del tipo del elemento de la colección y se pueden inicializar con el primer
valor de la colección, si la pregunta es existe o para todo la salida es un valor booleano
de cierto o falso. Podemos entonces refinar entonces el seudocódigo anterior:
Inicializa variable a devolver con un valor neutro
Para todo elemento de la colección
Si el elemento cumple la propiedad
variable = funcion (variable, elemento)
Finsi
FinPara
Devuelve variable
La función que actualiza variable lógicamente depende del problema: en un contador
será sumar uno, en una suma, sumar variable y elemento, en un existe será una
disyunción lógica entre variable y una propiedad de elemento, etc.
Concretemos el seudocódigo anterior en lenguaje C con varios ejercicios de enunciado
similar sobre una misma colección pero con preguntas diferentes. En todos los
Autor: José C. Riquelme (Universidad de Sevilla)
ejercicios se pide construir una función en C que reciba un array y devuelva un valor
sobre el mismo (suma, contador, máximo,…). El array será un parámetro constante
puesto que no se modificará en la función y como siempre la función deberá recibir
también el tamaño real del array, porque ya sabemos que no tiene por qué estar
completo.
2.1 Esquema contador. Dado un array de números reales y un umbral p codifique una
función que devuelva el número de elementos del array que son mayores estrictos que p.
 Entrada: un array de reales, un entero con el tamaño y un real con el umbral
 Salida: un entero con el contador
int contador(const TablaReales t, int n, float p){
int i;
int cont=0;
for (i=0;i<n;i++){
if (t[i]>p){
cont ++;
}
}
return cont;
}
2.2 Esquema suma. Dado un array de números reales y un umbral p codifique una
función que devuelva la suma de los elementos del array mayores estrictos que p.
 Entrada: un array de reales, un entero con el tamaño y un real con el umbral
 Salida: un real con la suma
float sumador(const TablaReales t, int n, float p){
int i;
float suma=0.;
for (i=0;i<n;i++){
if (t[i]>p){
suma = suma + t[i];
}
}
return suma;
}
2.2 Esquema existe. Dado un array de números reales y un umbral p codifique una
función que devuelva si existe algún elemento del array que sea mayor estricto que p.
 Entrada: un array de reales, un entero con el tamaño y un real con el umbral
 Salida: un lógico que devuelve cierto si existe y falso en caso contrario
Logico existe(const TablaReales t, int n, float p){
int i;
Logico hay=falso;
Tema 5. Tratamientos secuenciales
for (i=0;i<n;i++){
hay = hay || (t[i]>p);
}
return hay;
}
En este caso, el if sería redundante por eso se ha eliminado. Otra solución para este
problema sería:
Logico existe(const TablaReales t, int n, float p){
int i;
Logico hay=falso;
for (i=0;i<n;i++){
if ((t[i]>p){
hay = cierto;
break;
}
}
return hay;
}
La principal diferencia con respecto al esquema anterior es que el bucle termina cuando
encuentra un elemento cumpliendo la condición.
2.3 Esquema paraTodo. Dado un array de números reales y un umbral p codifique una
función que devuelva si todos los elementos del array son mayores estricto que p
 Entrada: un array de reales, un entero con el tamaño y un real con el umbral
 Salida: un lógico que devuelve cierto si todos cumplen y falso en caso contrario
Logico paraTodo(const TablaReales t, int n, float p){
int i;
Logico todo=cierto;
for (i=0;i<n;i++){
todo = todo && (t[i]>p);
}
return todo;
}
2.4 Esquema máximo sin filtro. Dado un array de números reales codifique una
función que devuelva el mayor de los elementos del array
 Entrada: un array de reales, un entero con el tamaño
 Salida: un valor real con el máximo del array
float maximo(const TablaReales t, int n){
int i;
float max;
Autor: José C. Riquelme (Universidad de Sevilla)
max=t[0];
for (i=0;i<n;i++){
max = mayor(max,t[i]);
}
return max;
}
float mayor(float x,float y){
float m;
if (x>y) m=x;
else m=y;
return m;
}
2.5 Esquema mínimo sin filtro. Dado un array de números reales codifique una
función que devuelva el menor de los elementos del array
 Entrada: un array de reales, un entero con el tamaño
 Salida: un real con el valor mínimo del array
float minimo(const TablaReales t, int n){
int i;
float min;
min=t[0];
for (i=0;i<n;i++){
min = menor(min,t[i]);
}
return min;
}
float menor(float x,float y){
float m;
if (x>y) m=y;
else m=x;
return m;
}
Los dos ejercicios de máximo y mínimo están suponiendo que en el array hay al menos
un elemento. Si n fuera 0 esta función podría dar un error de ejecución. Esa cuestión
debe ser indicada en la documentación de la función, de forma que cuando se invocara
en el programa principal debería comprobarse antes de su llamada. Esto es,
void main(void){
int numelem;
numelem = leeTabla(v);
if (numelem>0){
printf("maximo: %f\n",maximo(v,numelem));
printf("minimo: %f\n",minimo(v,numelem));
}
}
Tema 5. Tratamientos secuenciales
2.6 Esquemas máximo y mínimo con filtro. Calcular el máximo o mínimo de los
elementos de una colección que cumplan alguna condición, tiene una dificultad añadida
y es qué debería devolver la función si ningún elemento de la colección cumple la
condición. Además la inicialización de la variable a devolver tampoco se podría hacer
con el primer elemento pues puede que éste no cumpla la condición. Dejaremos este
ejercicio para más adelante.
3. Otros esquemas algorítmicos
Hay otros esquemas algorítmicos que no cumplen exactamente el patrón anterior pero se
aproximan bastante. En concreto son los esquemas de búsqueda y filtrado.
3.1 Esquema búsqueda. Dado un array de números reales y un valor real p devolver la
primera posición del array donde se encuentra p ó -1 si no estuviera.
 Entrada: un array de números reales, un entero con el tamaño, un valor real a
buscar
 Salida: un entero con la primera posición del primer elemento del array igual al
argumento que se busca ó -1 si no está.
int busca(const TablaReales t, int n, float p){
int i;
int pos=-1;
for(i=0;i<n;i++){
if (t[i]==p){
pos=i;
break;
}
}
return pos;
}
Obsérvese como el empleo de la sentencia break consigue que la primera vez que p es
encontrado se abandona el bucle de búsqueda. Si el problema en vez de localizar la
primera posición donde está p, buscara la última, en la solución anterior bastaría con
quitar el break.
El programa principal podría ser:
void main(void){
TablaReales v={1.2, 3.4, 5.4, 6.4, 7.8};
int pos;
float valor;
printf("Introduce valor a buscar: ");
scanf("%f",&valor);
pos = busca(v,5,valor);
Autor: José C. Riquelme (Universidad de Sevilla)
if (pos==-1)
printf("El elemento %f no está en el array\n",valor);
else
printf("El elemento %f está en la posición %d\n",valor,pos);
}
3.2 Esquema filtrado. Dado un array de números reales y un valor real p, devolver otro
array con los valores del primero que son mayores estrictos que p.
 Entrada: un array de números reales, un entero con el tamaño, un valor real
umbral.
 Salida: un array de números reales, un entero con su tamaño.
Este problema tiene una novedad con respecto a los resueltos anteriormente y es que por
primera vez la función a construir debe devolver dos datos diferentes: el array filtrado y
su tamaño. Debemos hacer hincapié otra vez que si se va a devolver un array con los
elementos filtrados a la función main, debe también devolverse el número de elementos
que tiene. Para ello y teniendo en cuenta que los arrays son argumentos que pueden
cambiar en la función si no se les pone la clausula const, haremos que la función
devuelva el tamaño del array filtrado en el nombre de la función.
int filtra(const TablaReales t, int n, TablaReales v, float p){
int i;
int pos=0;
for (i=0;i<n;i++){
if (t[i]>p){
v[pos]=t[i];
pos++;
}
}
return pos;
}
La función principal podría ser:
void main(void){
TablaReales v={1.2, 3.4, 5.4, 6.4, 7.8};
TablaReales v2;
int nelem;
float valor;
printf("Introduce valor umbral: ");
scanf("%f",&valor);
nelem = filtra(v,5,v2,valor);
imprime(v2,nelem);
}
Tema 5. Tratamientos secuenciales
Para visualizar en pantalla un array de reales podemos implementar una función
imprime:
void imprime(const TablaReales t, int n){
int i;
printf("\n[");
for(i=0;i<n-1;i++){
printf("%6.2f, ",t[i]);
}
printf("%6.2f ]\n",t[n-1]);
}
Donde el último elemento se imprime fuera del bucle para cerrar el corchete en vez de
poner una coma.
4. Problemas.
1. Construye una función que lea un entero n y a continuación lea n valores reales
y los guarde en un array.
Para cada una de las siguientes cuestiones cree una función que recibirá como argumentos
un array del tipo correspondiente, el número de elementos y si fuera necesario algún valor
más que se indique. Cada función devolverá el valor solicitado del tipo int, double o
Lógico.
2. Dado un array que contiene el registro diario de aumento de peso de un paciente
durante los 365 días de un año, indicar cuál ha sido el peso ganado (o perdido).
3. Dado un array que contiene los nucleótidos de una secuencia de ADN, indique
cuántas Timinas (‘T’) hay.
4. Generalice la función del problema anterior para que sea capaz de calcular
cuántos nucleótidos hay de cada tipo.
5. Dado un array de valores enteros escriba una función que devuelva el valor
máximo de entre los elementos pares.
6. Dado un array de valores de frecuencia cardiaca (enteros) y el intervalo
compuesto por dos valores [a, b], que pueden indicar los límites de la taquicardia
[100, 175] o la bradicardia [35, 60], escriba una función que indique si alguno de
los valores del array está comprendido en el intervalo.
7. Dado un array que contiene los datos de frecuencia cardiaco (enteros) de unos
pacientes, indicar cuál es el más bajo.
Autor: José C. Riquelme (Universidad de Sevilla)
8. Dado un array que contiene un codón (grupo de tres nucleótidos que codifican
un aminoácido) indique si se trata de Lisina (AAA).
9. Generalice el problema anterior a cualquier número de nucleótidos y cualquier
repetición de éstos.
10. Dado un array que representa una secuencia de ADN, donde cada posición
contiene un nucleótido, escriba una función que nos indique si alguno de los que
contiene es la Timina (‘T’).
11. Generalice el problema anterior para cualquier nucleótido.
12. Dado un array con los sueldos de unos empleados escriba una función que
indique si todos tienen un sueldo superior a 1000€.
13. Generalice la función a cualquier cantidad.
14. Dado un array con las edades de un grupo de personas, escriba una función que
devuelva otro array con los valores correspondientes a la edad de trabajar, es
decir, comprendida entre 16 y 65 años.
15. Generalice el problema anterior a otras edades por si cambia las edades de
primer contrato o jubilación.
16. Dado un array de valores reales y un intervalo compuesto por dos valores [a,b],
escriba una función que devuelva la posición en el array del primer elemento
que está contenido en el intervalo. En caso de que ninguno esté contenido,
devuelva el valor -1.
17. Dado un array con edades de pacientes de un hospital, donde cada posición en el
array se corresponde con la habitación que ocupa, indique en qué habitación se
encuentra el paciente más joven.
18. Dado un array de valores de ritmo cardiaco (enteros), filtre aquellos que están
por encima de los límites de normalidad (100).
19. Dado un array que contiene nucleótidos de una secuencia de ADN, recupere en
otro array todas aquellas apariciones de Adenina y Timina.
20. Dado un array que contiene nucleótidos de una secuencia de ADN, encuentre la
secuencia complementaria, esto es, una secuencia en la que la Adenina se
sustituya por Timina y la Guanina por Citosina.
Descargar