316 lines
11 KiB
Markdown
316 lines
11 KiB
Markdown
# PR 4
|
|
|
|
[Volver a la página principal de "Fundamentos de la Programación"](../README.md)
|
|
|
|
**Índice**
|
|
- [PR 4](#pr-4)
|
|
- [17. Esquemas de recorrido y búsqueda](#17-esquemas-de-recorrido-y-búsqueda)
|
|
- [17.1. Aproximación intuitiva](#171-aproximación-intuitiva)
|
|
- [17.1.1. Ejemplo 1 - Temperatura media](#1711-ejemplo-1---temperatura-media)
|
|
- [17.1.2. Ejemplo 2 - Recaudaciones de una sala de cine](#1712-ejemplo-2---recaudaciones-de-una-sala-de-cine)
|
|
- [17.2. Esquema de recorrido](#172-esquema-de-recorrido)
|
|
- [17.3. Esquema de búsqueda](#173-esquema-de-búsqueda)
|
|
- [17.3.1. Ejemplo](#1731-ejemplo)
|
|
|
|
|
|
## 17. Esquemas de recorrido y búsqueda
|
|
|
|
Ya hemos visto las estructuras secuencial, alternatica e iterativa, con esto, ya podemos resolver cualquier problema. Ahora vamos a ver esquemas de recorrido y búsqueda, que son una especie de patrones o estructuras predeterminadas para diseñar algoritmos de manera más sistemática y ganar en eficiencia y fiabilidad.
|
|
|
|
Un esquema es una especie de plantilla que nos permite solucionar un tipo de problema específico con adaptaciones a cada caso concreto. Un ejemplo de aplicación de esquemas de recorrido y búsqueda es para resolver problemas de tratamiento de secuencias de manera más eficiente y sistemática.
|
|
|
|
|
|
### 17.1. Aproximación intuitiva
|
|
|
|
La idea es que, en lugar de ir a ciegas, sigamos un esquema de recorrido o búsqueda que nos permita ir avanzando de manera sistemática y eficiente. Por ejemplo, si tenemos que recorrer una matriz, podemos hacerlo por filas o por columnas, o si tenemos que buscar un elemento en una lista, podemos hacerlo de manera secuencial o binaria.
|
|
|
|
|
|
#### 17.1.1. Ejemplo 1 - Temperatura media
|
|
|
|
Vamos a calcular la temperatura media de todo el año suponiendo que vamos leyendo por el canal de entrada las temperaturas medias de cada día:
|
|
|
|
```alg
|
|
algorithm averageTemp
|
|
var
|
|
temperature: real;
|
|
average: real;
|
|
i: integer;
|
|
end var
|
|
|
|
i:= 0;
|
|
average:= 0;
|
|
|
|
while i < 365 do
|
|
temperature:= readReal();
|
|
average:= average + temperature;
|
|
i:= i + 1;
|
|
end while
|
|
|
|
write(average / 365.0);
|
|
|
|
end algorithm
|
|
```
|
|
|
|
```c
|
|
#include <stdio.h>
|
|
|
|
int main(int argc, char** argv) {
|
|
float temperature;
|
|
float average;
|
|
int i;
|
|
|
|
i = 0;
|
|
average = 0;
|
|
|
|
while (i < 365) {
|
|
scanf("%f", &temperature);
|
|
average = average + temperature;
|
|
i = i + 1;
|
|
}
|
|
|
|
printf("%f\n", average / 365.0);
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
|
|
#### 17.1.2. Ejemplo 2 - Recaudaciones de una sala de cine
|
|
|
|
Cargamos los datos de una tabla de recaudaciones de una sala de cine a partir de lo leído por el canal de entrada estándar.
|
|
|
|
```alg
|
|
const
|
|
MAX_THEATERS: integer = 20;
|
|
END_SEQ: real = -1.0;
|
|
end const
|
|
|
|
type
|
|
tTheater = record
|
|
collect: vector[MAX_THEATERS] real;
|
|
numTheaters: integer;
|
|
end record
|
|
end type
|
|
|
|
action fillTable(inout movieTheater:tTheater);
|
|
|
|
var
|
|
i: integer;
|
|
temp: real;
|
|
end var
|
|
|
|
temp:= readReal(); {We read the first value}
|
|
movieTheater.numTheaters:= 0;
|
|
|
|
while temp ≠ END_SEQ do
|
|
movieTheater.numTheaters:= movieTheater.numTheaters + 1;
|
|
movieTheater.collect[movieTheater.numTheaters]:= temp;
|
|
temp:= readReal();
|
|
end while
|
|
|
|
end action
|
|
```
|
|
|
|
```c
|
|
#include <stdio.h>
|
|
#define END_SEQ -1
|
|
#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 */
|
|
temp = 0;
|
|
movieTheater->numTheaters = 0;
|
|
scanf("%f", &temp); /* read the first value */
|
|
|
|
/* 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);
|
|
}
|
|
}
|
|
```
|
|
|
|
|
|
### 17.2. Esquema de recorrido
|
|
|
|
En los dos ejemplos anteriores estamos haciendo un recorrido a través de una serie de datos repitiendo el mismo esquema:
|
|
|
|
1. Acceso al primer elemento. En el primer ejemplo, leemos el primer valor de la temperatura y en el segundo, leemos el primer valor de la tabla.
|
|
2. Tratamiento inicial. Inicializamos las variables que utilizaremos para hacer el tratamiento posterior.
|
|
3. Último elemento. Comprobamos si hemos llegado al último elemento.
|
|
4. Trater elemento. Aplicamos las acciones necesarias para resolver cada uno de los datos a tratar.
|
|
5. Acceso al siguiente elemento.
|
|
6. Tratamiento final. Terminar las acciones que queden por resolver el problema.
|
|
|
|
**Ejemplo 1**
|
|
|
|
| Partes | Código |
|
|
| ------------------------------------------------ | ---------------------------------------------------------------------------------- |
|
|
| Acceso al primer elemento | `i := 1;` |
|
|
| Tratamiento inicial | `media := 0;` |
|
|
| Comprobar si ya hemos llegado al último elemento | `while i <= 365 do` |
|
|
| Tratar el elemento | `temperatura := readReal();` <br> `media := media + temperatura;` <br> `end while` |
|
|
| Acceso al siguiente elemento | `i := i + 1` |
|
|
| Tratamiento final | `writeReal(media/365.0)` |
|
|
|
|
**Ejemplo 2**
|
|
|
|
| Partes | Código |
|
|
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
| Acceso al primer elemento | `temp := readReal();` |
|
|
| Tratamiento inicial | `movieTheater.numTheaters := 0;` |
|
|
| Comprobar si ya hemos llegado al último elemento | `while temp ≠ END_SEQ do` |
|
|
| Tratar el elemento | `movieTheater.numTheaters := movieTheater.numTheaters + 1;`<br>`movieTheater.collect[movieTheater.numTheaters] := temp;` <br> `end while` |
|
|
| Acceso al siguiente elemento | `temp := readReal();` |
|
|
| Tratamiento final | - |
|
|
|
|
Con lo cual, en estos dos casos se comparte el **esquema de recorrido**, ya sea para recorrer datos que leemos del canal estándar o datos de una tabla. Un patrón habitual es el siguiente:
|
|
|
|
```alg
|
|
algorithm esquemaRecorrido
|
|
|
|
{acceder al primer elemento}
|
|
{tratamiento inicial}
|
|
|
|
while not {último elemento} do
|
|
{tratar elemento}
|
|
{acceder al siguiente elemento}
|
|
end while
|
|
|
|
{tratamiento final}
|
|
|
|
end algorithm
|
|
```
|
|
|
|
Tener en cuenta que:
|
|
- Todos los elementos de la secuencia son del mismo tipo.
|
|
- Procesamos todos los elementos de la misma manera.
|
|
- Es necesario saber cómo se acaba la secuencia.
|
|
|
|
|
|
### 17.3. Esquema de búsqueda
|
|
|
|
Vamos a ver un ejemplo que es lo más esclarecedor.
|
|
|
|
|
|
#### 17.3.1. Ejemplo
|
|
|
|
A partir de las temperaturas medias de un año que leemos por el canal estándar, averiguar el primer día que ha helado. Debemos comprobar que la temperatura es negativa.
|
|
|
|
```alg
|
|
algorithm hasFrozen
|
|
|
|
var
|
|
t: vector[365] real;
|
|
frost: boolean;
|
|
i: integer;
|
|
end var
|
|
|
|
i:= 1;
|
|
frost:= false;
|
|
|
|
while i ≤ 365 and frost == false do
|
|
t[i]:=readReal();
|
|
if t[i] ≤ 0 then
|
|
frost:= true;
|
|
end if
|
|
i:=i+1:
|
|
end while
|
|
|
|
writeBoolean(frost);
|
|
|
|
end algorithm
|
|
```
|
|
|
|
```c
|
|
#include <stdio.h>
|
|
#include <stdbool.h>
|
|
|
|
int main(int argc, char** argv) {
|
|
float t[365];
|
|
bool frost;
|
|
int i;
|
|
|
|
i = 0;
|
|
frost = false;
|
|
|
|
while (i < 365 && !frost) {
|
|
scanf("%f", &t[i]);
|
|
if (t[i] <= 0) {
|
|
frost = true;
|
|
}
|
|
i = i + 1;
|
|
}
|
|
|
|
printf("%d\n", frost); /* Equivalence in C language: 0 == false, 1 == true */
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
Cuando encontramos el primer caso de temperatura negativa ya podemos dejar de buscar, hemos realizado una **búsqueda**. Otro caso sería si quisieramos saber cuántos días ha helado, que tendríamos que hacer un **recorrido** por todas las temperaturas.
|
|
|
|
Los pasos del esquema de búsqueda son:
|
|
1. Acceder al primer elemento.
|
|
2. Tratamiento inicial.
|
|
3. Último elemento
|
|
4. Actualizar encontrado
|
|
5. Acceder al siguiente elemento.
|
|
6. Tratamiento final.
|
|
|
|
| Partes | Código |
|
|
| ------------------------------------------------ | ------------------------------------------------------------------------ |
|
|
| Acceso al primer elemento | `i := 1;` |
|
|
| Tratamiento inicial | no hace falta inicializar ninguna variable; <br> `encontrado := false;` |
|
|
| Comprobar si ya hemos llegado al último elemento | `while i <= 365 and not encontrado do` |
|
|
| Actualizar encontrado | `t[i] := readReal();` <br> `if t[i] ≤ 0 entonces encontrado:= true;` |
|
|
| Acceso al siguiente elemento | `if not encontrado then` <br> `i:= i +1;` <br> `end if` <br> `end while` |
|
|
| Tratamiento final | `writeBoolean(encontrado)` |
|
|
|
|
Por lo tanto, este sería el **esquema de búsqueda**:
|
|
|
|
```alg
|
|
algorithm esquemaBusqueda
|
|
var
|
|
encontrado: boolean;
|
|
end var
|
|
|
|
{acceder_primer_elemento}
|
|
{tratamiento_inicial}
|
|
|
|
encontrado:= false;
|
|
|
|
while not {último elemento} and not encontrado do
|
|
if {elemento tratado cumple condición} then
|
|
encontrado:= true;
|
|
else
|
|
{acceder al siguiente elemento}
|
|
end if
|
|
end while
|
|
|
|
{tratamiento_final}
|
|
|
|
end algorithm
|
|
```
|
|
|
|
Tener en cuenta que:
|
|
- Recorremos únicamente la secuencia hasta encontrar el elemento que cumple una determinada condición.
|
|
- Se contempla la posibilidad de que no se encuentre el elemento buscado.
|
|
- El esquema finaliza si se encuentra el elemento buscado o si se ha recorrido toda la secuencia.
|
|
|
|
|
|
[Volver arriba](#pr-4)
|
|
|
|
[Volver a la PR3](../PR3/README.md) | [Seguir a la PEC 6](../PEC6/README.md)
|