Estructuras de Datos y Algoritmos (ITIS)
Estructuras de Datos y Algoritmos (ITIS)
Estructuras de Datos y Algoritmos (ITIS)
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
<strong>Estructuras</strong> <strong>de</strong> <strong>Datos</strong> y <strong>Algoritmos</strong> (<strong>ITIS</strong>). TAD Lineales<br />
<strong>Estructuras</strong> <strong>de</strong> <strong>Datos</strong> y <strong>Algoritmos</strong> (<strong>ITIS</strong>)<br />
Ingeniería Técnica en Informática <strong>de</strong> Sistemas, Curso 2º<br />
PRÁCTICA 2<br />
TAD LINEALES<br />
SIMULACIÓN DE UN CENTRO DE INFORMACIÓN<br />
Las colas pue<strong>de</strong>n utilizarse para mo<strong>de</strong>lar líneas <strong>de</strong> espera (colas <strong>de</strong> espera). De hecho, la teoría <strong>de</strong><br />
colas es un área tan importante en informática, investigación operativa y matemática aplicada que<br />
existe una extensa bibliografía <strong>de</strong>dicada a ella. Por ejemplo, en un contexto <strong>de</strong> sistemas operativos, las<br />
colas <strong>de</strong> espera se forman cuando más <strong>de</strong> un proceso necesita un recurso (impresora, disco, CPU, etc.).<br />
Cuando los procesos pi<strong>de</strong>n un recurso, se colocan en una cola esperando ser atendidos por dicho<br />
recurso. También, las colas se pue<strong>de</strong>n utilizar para planificar las tareas mientras van pasando por<br />
diferentes estados en el scheduler <strong>de</strong>l sistema operativo. Es preciso <strong>de</strong>stacar que en los schedulers<br />
actuales la cola <strong>de</strong> procesos listos no es simplemente una cola FIFO, sino que se utiliza una<br />
planificación más sofisticada don<strong>de</strong> los procesos tienen asignada una prioridad (que pue<strong>de</strong> cambiar<br />
dinámicamente), y que pare ello se suelen utilizar colas <strong>de</strong> prioridad.<br />
La mayoría <strong>de</strong> las líneas <strong>de</strong> espera son dinámicas, es <strong>de</strong>cir, sus longitu<strong>de</strong>s cambian en el tiempo,<br />
creciendo cuando llegan nuevos elementos y se aña<strong>de</strong>n a las colas, y disminuyendo cuando se eliminan<br />
elementos <strong>de</strong> las colas y son atendidos. El término simulación se refiere al mo<strong>de</strong>lado <strong>de</strong> este proceso<br />
dinámico y la utilización <strong>de</strong> este mo<strong>de</strong>lo para estudiar el comportamiento <strong>de</strong> un proceso <strong>de</strong>terminado.<br />
El comportamiento <strong>de</strong> algunos procesos <strong>de</strong>terministas pue<strong>de</strong> ser mo<strong>de</strong>lado con una ecuación o un<br />
conjunto <strong>de</strong> ecuaciones. Por ejemplo, los procesos que tienen un crecimiento o <strong>de</strong>crecimiento<br />
exponencial se mo<strong>de</strong>lan comúnmente mediante una ecuación <strong>de</strong> la forma A(t) = A 0 e kt , don<strong>de</strong> A(t) es la<br />
cantidad <strong>de</strong> algún elemento A presente en el instante <strong>de</strong> tiempo t, A 0 es la cantidad inicial <strong>de</strong> este<br />
elemento y k es una constante.<br />
Sin embargo, en muchos problemas, el proceso en estudio tiene cierta aleatoriedad; por ejemplo, la<br />
llegada <strong>de</strong> aviones a un aeropuerto, el número <strong>de</strong> piezas <strong>de</strong>fectuosas manufacturadas por una máquina,<br />
una fila <strong>de</strong> personas esperando para pagar en un <strong>de</strong>terminado establecimiento (supermercado,<br />
gasolinera, peaje, etc.), etc. Por ejemplo, las colas utilizan para mo<strong>de</strong>lar filas <strong>de</strong> espera que se producen<br />
en una <strong>de</strong>terminada operación <strong>de</strong> un sistema informático. Los programas que simulan tales procesos<br />
utilizan un generador <strong>de</strong> números aleatorios para introducir aleatoriedad en los valores generados<br />
durante la ejecución. Ésta es una función que genera un número seleccionado aleatoriamente <strong>de</strong> entre<br />
un rango fijo, <strong>de</strong> tal manera que una secuencia <strong>de</strong> estos números se distribuye uniformemente en el<br />
rango dado. Aunque los números realmente aleatorios se generan con procesos aleatorios físicos,<br />
algunas fórmulas matemáticas generan secuencias <strong>de</strong> números pseudoaleatorios que son a<strong>de</strong>cuados en<br />
la mayoría <strong>de</strong> las situaciones.<br />
Página 1
<strong>Estructuras</strong> <strong>de</strong> <strong>Datos</strong> y <strong>Algoritmos</strong> (<strong>ITIS</strong>). TAD Lineales<br />
El comportamiento <strong>de</strong> una cola también conlleva cierta aleatoriedad, porque generalmente no se<br />
conoce <strong>de</strong> antemano cuándo llegará exactamente un nuevo elemento o cuánto tiempo se necesitará para<br />
servir a un elemento especificado. Como caso <strong>de</strong> estudio e implementación en esta práctica,<br />
consi<strong>de</strong>ramos el funcionamiento <strong>de</strong> un centro <strong>de</strong> información y reservas que atien<strong>de</strong> llamadas gratuitas<br />
hechas por clientes, como las proporcionadas por compañías aéreas o <strong>de</strong> alquiler <strong>de</strong> coches. Cuando<br />
llega una llamada a este centro, se coloca en una cola <strong>de</strong> llamadas entrantes; cuando un agente se<br />
encuentra libre, atien<strong>de</strong> la llamada al comienzo <strong>de</strong> la cola.<br />
Análisis y especificación <strong>de</strong>l problema<br />
La simulación <strong>de</strong>bería proce<strong>de</strong>r <strong>de</strong> la siguiente manera. Un cronómetro <strong>de</strong>scen<strong>de</strong>nte simulado se<br />
inicializa con los minutos en los que se aceptarán llamadas y repetidamente se va <strong>de</strong>crementando <strong>de</strong><br />
uno en uno hasta que llegue a cero. En cada tic <strong>de</strong>l reloj se comprueba si ya se ha terminado el servicio<br />
<strong>de</strong> la llamada actual, y si es así, se elimina <strong>de</strong> la cola <strong>de</strong> llamadas entrantes y se comienza el servicio<br />
simulado <strong>de</strong> la siguiente llamada en la cola (si hay alguna). También se comprueba si ha llegado una<br />
nueva llamada. Si es así, se almacena su tiempo <strong>de</strong> llegada, se genera un tiempo <strong>de</strong> servicio aleatorio y<br />
se almacena, y la llamada se coloca en la cola para que sea procesada <strong>de</strong> la forma primero-en-llegarprimero-en-ser-servido<br />
(FIFO, First-In-First-Out) cuando un agente se libera. Cuando el contador llega<br />
a cero, no se aceptan nuevas llamadas, pero el servicio continúa hasta que todas las llamadas <strong>de</strong> la cola<br />
sean procesadas.<br />
Como hemos indicado anteriormente, la simulación se realiza para un periodo <strong>de</strong> tiempo<br />
especificado, por lo que un dato <strong>de</strong> entrada será un tiempo límite. Ya que hay que simular la llegada y<br />
el servicio <strong>de</strong> llamadas, también se necesita información sobre la tasa <strong>de</strong> llegadas y los tiempos <strong>de</strong><br />
servicio. Por tanto, la entrada tendrá el siguiente formato:<br />
Entrada:<br />
Tiempo límite<br />
Tasa <strong>de</strong> llegada <strong>de</strong> llamadas<br />
Distribución <strong>de</strong> los tiempos <strong>de</strong> servicio<br />
Cuando se complete la simulación, <strong>de</strong>ben ofrecerse estadísticas que midan el rendimiento <strong>de</strong>l centro <strong>de</strong><br />
información. Aquí mostraremos sólo dos <strong>de</strong> dichas estadísticas:<br />
Salida:<br />
Número <strong>de</strong> llamadas procesadas<br />
Tiempo medio <strong>de</strong> espera por llamada<br />
Construcción <strong>de</strong> una clase CSimulacion<br />
Atributos. Los tres datos <strong>de</strong> entrada y los dos <strong>de</strong> salida son los valores básicos involucrados en la<br />
simulación. Un objeto <strong>de</strong> la clase CSimulacion almacenará estos cinco valores en sus atributos.<br />
El primer atributo, miLongitudSimulacion, almacena el tiempo límite <strong>de</strong> la simulación. El valor<br />
<strong>de</strong>l segundo atributo, miTasaLlegadas, es la probabilidad <strong>de</strong> que llegue una llamada en un minuto<br />
dado. Por ejemplo, si el tiempo medio entre llamadas es <strong>de</strong> cinco minutos, entonces la tasa <strong>de</strong> llegadas<br />
es 1/5 = 0,2 llamadas por minuto. El tercer atributo es un vector miPorcentajeServicios, que<br />
almacena información sobre el tiempo necesario para aten<strong>de</strong>r una llamada:<br />
miPorcentajeServicios [0] = porcentaje <strong>de</strong> llamadas atendidas en 1 minuto o menos<br />
Página 2
<strong>Estructuras</strong> <strong>de</strong> <strong>Datos</strong> y <strong>Algoritmos</strong> (<strong>ITIS</strong>). TAD Lineales<br />
miPorcentaj eServicios [1] = porcentaje <strong>de</strong> llamadas atendidas en 2 minutos o menos<br />
miPorcentajeServicios[2] = porcentaje <strong>de</strong> llamadas atendidas en 3 minutos o menos<br />
En nuestra clase CSimulacion, utilizaremos NUM_CATEGORIAS = 5 categorías <strong>de</strong> tiempos necesarios<br />
para aten<strong>de</strong>r una llamada entrante. El usuario introduce los porcentajes <strong>de</strong> llamadas que requieren 1, 2,<br />
3, 4 o 5 minutos, y éstos son acumulados para obtener los valores <strong>de</strong> miPorcentajeServicios. Por<br />
ejemplo, si el usuario introduce 50, 25, 15, 7 y 3, los valores almacenados en el vector<br />
miPorcentajeServicios son 50, 75 (= 50 + 25), 90 (= 50 + 25 + 15), 97 (= 50 + 25 + 15 + 7) y 100<br />
(la suma <strong>de</strong> todos los porcentajes):<br />
[0] [1] [2] [3] [4]<br />
miPorcentajeServicios 50 75 90 97 100<br />
Otros atributos necesarios serán un cronómetro <strong>de</strong>scen<strong>de</strong>nte miCrono <strong>de</strong> tipo CReloj, una clase que<br />
<strong>de</strong>scribiremos más a<strong>de</strong>lante, y una cola misLlamadasEntrantes <strong>de</strong> llamadas entrantes. Utilizaremos el<br />
TAD genérico queue <strong>de</strong> la STL <strong>de</strong> C++ para implementar la cola <strong>de</strong> llamadas, y su tipo <strong>de</strong> elementos<br />
será CLlamada, una clase para mo<strong>de</strong>lar llamadas que <strong>de</strong>scribiremos más a<strong>de</strong>lante. La <strong>de</strong>claración <strong>de</strong> la<br />
cola será <strong>de</strong> la siguiente manera: queue misLlamadasEntrantes;<br />
A continuación mostraremos la estructura <strong>de</strong> la clase CSimulacion con estos atributos y operaciones<br />
básicas en el archivo cabecera. Las operaciones básicas necesarias para realizar la simulación son:<br />
constructor: construye un objeto <strong>de</strong> la clase CSimulacion, ejecutar(): lleva a cabo la simulación<br />
(ejecutar la simulación), comprobarLlamadasNuevas(): comprueba si ha llegado una llamada nueva<br />
(requerirá comprobar si han llegado llamadas nuevas), aten<strong>de</strong>r(): atien<strong>de</strong> una llamada entrante<br />
(servicio <strong>de</strong> llamadas entrantes), y mostrar(): muestra los resultados <strong>de</strong> la simulación (mostrará los<br />
resultados cuando termine la simulación).<br />
La clase CSimulacion:<br />
// CSimulacion.h<br />
#inclu<strong>de</strong> // istream, ostream, >>,
<strong>Estructuras</strong> <strong>de</strong> <strong>Datos</strong> y <strong>Algoritmos</strong> (<strong>ITIS</strong>). TAD Lineales<br />
int miLongitudSimulacion;<br />
double miTasaLlegadas;<br />
int miPorcentajeServicios[NUM_CATEGORIAS];<br />
int misLlamadasRecibidas;<br />
double miTiempoTotalEspera;<br />
CReloj miReloj;<br />
};<br />
queue misLlamadasEntrantes;<br />
#endif<br />
Constructor. El constructor <strong>de</strong> la clase CSimulacion inicializa los atributos necesarios para realizar la<br />
simulación y generar los resultados. Los tres atributos <strong>de</strong> entrada se inicializan en el constructor<br />
utilizando valores introducidos durante la ejecución. Los dos atributos <strong>de</strong> salida,<br />
misLlamadasRecibidas y miTiempoEsperaTotal, almacenan los valores necesarios cuando se<br />
produce la salida <strong>de</strong> los resultados y se inicializan a 0. Los otros dos atributos, miReloj y<br />
misLlamadasEntrantes, son objetos <strong>de</strong> tipo CReloj y queue, respectivamente, y son inicializados por<br />
sus constructores. El constructor también inicializa el generador <strong>de</strong> números aleatorios rand()<br />
proporcionado por la librería , utilizando srand() <strong>de</strong> la misma librería y la hora <strong>de</strong>l reloj<br />
obtenida <strong>de</strong>s<strong>de</strong> .<br />
El método ejecutar(). El método ejecutar() <strong>de</strong> la clase CSimulacion es la operación que inicia y<br />
controla la simulación. Implementa el siguiente algoritmo:<br />
Algoritmo para ejecutar la simulación<br />
1. Inicializa tiempoEsperaRestante a 0, haciendo el servicio disponible para la primera llamada<br />
entrante. Esta variable indica en cada momento <strong>de</strong> la simulación, cuánto tiempo tiene que pasar<br />
hasta que se atienda una nueva llamada.<br />
2. Mientras miReloj no haya terminado:<br />
a. Continuar el servicio <strong>de</strong> la llamada anterior o comenzar el servicio <strong>de</strong> la siguiente<br />
llamada en la cola misLlamadasEntrantes (si hay alguna).<br />
b. Comprobar si ha llegado una nueva llamada y, si es así, añadirla a la cola<br />
misLlamadasEntrantes.<br />
c. Hacer que miReloj avance una unidad <strong>de</strong> tiempo.<br />
3. Mientras que<strong>de</strong>n llamadas pendientes en la cola,<br />
a. Aten<strong>de</strong>r la llamada al frente <strong>de</strong> la cola.<br />
b. Hacer que miReloj avance una unidad <strong>de</strong> tiempo.<br />
4. Mostrar los resultados.<br />
Los pasos 2a y 3a los realiza el método aten<strong>de</strong>r(); el paso 2b comprobarLlamadasNuevas(); los<br />
pasos 2c y 3b se consiguen enviando un mensaje a miReloj utilizando su método tic(); y el paso 4<br />
mostrar().<br />
El método aten<strong>de</strong>r(). El método aten<strong>de</strong>r() <strong>de</strong> la clase CSimulacion atien<strong>de</strong> cada llamada al llegar<br />
al frente <strong>de</strong> la cola misLlamadasEntrantes. Implementa el siguiente algoritmo:<br />
Página 4
<strong>Estructuras</strong> <strong>de</strong> <strong>Datos</strong> y <strong>Algoritmos</strong> (<strong>ITIS</strong>). TAD Lineales<br />
Algoritmo para aten<strong>de</strong>r una llamada<br />
Comprobar si tiempoEsperaRestante > 0. Si es así, esto significa que se está atendiendo una<br />
llamada actualmente, por lo que sólo se <strong>de</strong>crementa tiempoEsperaRestante en 1 para indicar<br />
que la llamada ha sido atendida durante otro minuto.<br />
En otro caso, hacer lo siguiente:<br />
Si la cola misLlamadasEntrantes no está vacía:<br />
a. Obtener y eliminar siguienteLlamada <strong>de</strong>l frente <strong>de</strong> misLlamadasEntrantes.<br />
b. Hacer tiempoEsperaRestante = el tiempo <strong>de</strong> servicio <strong>de</strong> siguienteLlamada para<br />
indicar que el servicio <strong>de</strong> esta llamada comienza.<br />
c. Actualizar miTiempoEsperaTotal, el tiempo <strong>de</strong> espera total para todas las<br />
llamadas <strong>de</strong> la cola misLlamadasEntrantes, sumándole (tiempo <strong>de</strong> llegada <strong>de</strong><br />
siguienteLlamada) - (tiempo restante <strong>de</strong> miReloj).<br />
El método comprobarLlamadasNuevas(). A continuación mostramos el algoritmo que <strong>de</strong>be<br />
implementarse para este método:<br />
Algoritmo para comprobar la llegada <strong>de</strong> una nueva llamada<br />
1. Generar un entero aleatorio x en el rango <strong>de</strong> 0 a 100.<br />
2. Si x < 100 * miTasaLlegadas<br />
// Esto se interpreta como la llegada <strong>de</strong> una nueva llamada:<br />
Llega una<br />
llamada<br />
No llegan<br />
llamadas<br />
t<br />
0 20 100<br />
a. Generar un nuevo número aleatorio r en el rango <strong>de</strong> 0 a 100. Se utilizará para <strong>de</strong>terminar<br />
el tiempo <strong>de</strong> servicio <strong>de</strong> la llamada.<br />
b. Determinar la categoría <strong>de</strong> servicios correspondiente, encontrando el menor índice i para<br />
el cual r
<strong>Estructuras</strong> <strong>de</strong> <strong>Datos</strong> y <strong>Algoritmos</strong> (<strong>ITIS</strong>). TAD Lineales<br />
intervalo (0, 100); el subintervalo en el que cae (0,50], (50, 75], (75, 90], (90, 97] o (97, 100] <strong>de</strong>termina<br />
el tiempo <strong>de</strong> servicio <strong>de</strong> la llamada:<br />
Tiempo <strong>de</strong><br />
servicio<br />
1<br />
2 3 4 5<br />
t<br />
0 50 75 90 97 100<br />
El método mostrar(). Al finalizar la simulación, se muestran el número total <strong>de</strong> llamadas procesadas<br />
o atendidas y el tiempo medio <strong>de</strong> espera por llamada. El número <strong>de</strong> llamadas se almacena en el atributo<br />
misLlamadasRecibidas, y la espera media pue<strong>de</strong> calcularse dividiendo miTiempoEsperaTotal por<br />
misLlamadasRecibidas.<br />
Las clases CReloj y CLlamada<br />
Otro objeto <strong>de</strong> la simulación es el cronómetro <strong>de</strong>scen<strong>de</strong>nte, mo<strong>de</strong>lado por la clase CReloj cuyas<br />
operaciones básicas son las siguientes:<br />
constructor: construye un objeto CReloj con un tiempo inicial especificado (por <strong>de</strong>fecto 0<br />
minutos)<br />
encen<strong>de</strong>r(): modificador para encen<strong>de</strong>r/apagar el reloj<br />
tic(): <strong>de</strong>crementa el cronómetro en una unidad <strong>de</strong> tiempo<br />
tiempoRestante(): <strong>de</strong>termina cuánto tiempo falta<br />
Sólo tiene un atributo (misMinutos).<br />
//* CReloj.h<br />
#ifn<strong>de</strong>f CRELOJ_H<br />
#<strong>de</strong>fine CRELOJ_H<br />
class CReloj<br />
{<br />
public:<br />
CReloj (int tiempoInicial = 0);<br />
void encen<strong>de</strong>r(int minutos);<br />
void tic();<br />
int tiempoRestante() const;<br />
private:<br />
int misMinutos;<br />
};<br />
#endif<br />
Otro objeto es una llamada al centro <strong>de</strong> información, mo<strong>de</strong>lada por la clase CLlamada con las<br />
siguientes operaciones básicas:<br />
constructor: construye un objeto CLlamada inicializado con un tiempo <strong>de</strong> llegada y <strong>de</strong> servio<br />
<strong>de</strong>terminados aleatoriamente (por <strong>de</strong>fecto 0)<br />
obtenerTiempoLlegada(): operación observadora para obtener el tiempo <strong>de</strong> llegada<br />
obtenerTiempoServicio(): obtiene el tiempo necesario para aten<strong>de</strong>r la llamada<br />
mostrar(): muestra la información <strong>de</strong> la llamada<br />
Página 6
<strong>Estructuras</strong> <strong>de</strong> <strong>Datos</strong> y <strong>Algoritmos</strong> (<strong>ITIS</strong>). TAD Lineales<br />
<strong>Estructuras</strong> <strong>de</strong> <strong>Datos</strong> y <strong>Algoritmos</strong> (<strong>ITIS</strong>). TAD Lineales<br />
Ejercicios prácticos relacionados con TAD Lineales.<br />
1. Ejercicio con pilas. Evaluación <strong>de</strong> expresiones postfijas (RPN, Reverse Polish Notation, Notación<br />
Polaca Invertida). La mayoría <strong>de</strong> los lenguajes <strong>de</strong> programación, las expresiones aritméticas se escriben<br />
en notación infija (por ejemplo, a * b + c – d), en la que los símbolos <strong>de</strong> las operaciones binarias se<br />
colocan entre los operandos. Muchos compiladores transforman primero estas expresiones infijas en<br />
notación postfija, en la que el operador sigue a los operandos, y a continuación generan instrucciones<br />
máquina para evaluar estas expresiones postfijas. Se utiliza este proceso <strong>de</strong> dos pasos porque la<br />
transformación <strong>de</strong> notación infija a postfija es inmediata y las expresiones postfijas, en general, son<br />
más sencillas <strong>de</strong> evaluar que las expresiones infijas. A<strong>de</strong>más, para las expresiones en notación infija, a<br />
menudo se necesitan paréntesis para señalar el or<strong>de</strong>n <strong>de</strong> las operaciones (teniendo en cuenta las reglas<br />
<strong>de</strong> prece<strong>de</strong>ncia habituales). Para la notación postfija los paréntesis no son necesarios. Por ejemplos, la<br />
expresión infija 2*(3+4) se pue<strong>de</strong> escribir en notación postfija como 234+*.<br />
Como ejemplo <strong>de</strong> cómo se evalúan las expresiones postfijas, veámoslo con un ejemplo. 15+841--*<br />
(equivalente a (1+5)*(8 – (4 – 1)) en infija). Dicha expresión se lee <strong>de</strong> izquierda a <strong>de</strong>recha hasta que se<br />
encuentra a un operador. En este momento, se combinan los dos operandos anteriores utilizando dicho<br />
operador. 15+841--* ⇔ 6841--* ⇔ 683-* ⇔ 683-* ⇔ 65* ⇔ 30.<br />
Este método <strong>de</strong> evaluación <strong>de</strong> una expresión postfija requiere que los operandos se almacenen hasta<br />
que se encuentre un operador durante la lectura <strong>de</strong> izquierda a <strong>de</strong>recha. En este momento, se recuperan<br />
los dos últimos operandos y se combinan utilizando el operador. Lo que sugiere el uso <strong>de</strong> una pila para<br />
guardar los operandos. Cada vez que se encuentra un operando, se apila. Y cuando se encuentra un<br />
operador los dos valores superiores se <strong>de</strong>sapilan; la operación se aplica sobre ellos y el resultado se<br />
vuelve a apilar. El siguiente algoritmo resume este procedimiento:<br />
// Escribir una expresión postfija (en un string) y <strong>de</strong>volver su valor a menos que ocurra un error<br />
// Utilizar una pila para almacenar los operandos<br />
1. Crear una pila vacía<br />
2. Repetir lo siguiente hasta que se encuentre el final <strong>de</strong> la expresión<br />
2.1. Obtener el siguiente elemento (constante, variable, operador aritmético) <strong>de</strong> la expresión<br />
postfija<br />
2.2. Si el elemento es un operando, apilarlo en la pila. Si es un operador, hacer lo siguiente<br />
2.2.1. Desapilar dos valores <strong>de</strong> la pila (si la pila no contiene dos valores, se tiene un<br />
error <strong>de</strong>bido a que la expresión postfija estaba mal formada y se termina la evaluación<br />
2.2.2. Aplicar el operador a estos dos valores<br />
2.2.3. Apilar el resultado<br />
3. Cuando se llegue al final <strong>de</strong> la expresión, su valore se encontrará en la cima <strong>de</strong> la pila. En<br />
realidad, <strong>de</strong>be ser el último valor en la pila, y si no lo es, se ha producido un error <strong>de</strong>bido a que la<br />
expresión postfija estaba mal formada<br />
Se pi<strong>de</strong>: implementar en C++ el anterior algoritmo para evaluar expresiones postfijas en <strong>de</strong>cimal (los<br />
operadores permitidos serán: +, -, *. /), haciendo uso <strong>de</strong> los TAD <strong>de</strong> la STL <strong>de</strong> C++ que consi<strong>de</strong>re<br />
necesarios (por ejemplo, stack). Para probarlo, muestre el seguimiento (la traza <strong>de</strong> ejecución) <strong>de</strong>l<br />
algoritmo y <strong>de</strong> las estructuras <strong>de</strong> datos más representativas para la siguiente expresión postfija:<br />
24*95+-<br />
Página 8
<strong>Estructuras</strong> <strong>de</strong> <strong>Datos</strong> y <strong>Algoritmos</strong> (<strong>ITIS</strong>). TAD Lineales<br />
2. Ejercicio con colas. Problema <strong>de</strong> entrenamiento. Se <strong>de</strong>sea diseñar un programa que proporcione<br />
ejercicios <strong>de</strong> entrenamiento sobre aritmética básica. Más concretamente, cada ejercicio requiere <strong>de</strong> la<br />
ejecución <strong>de</strong> una operación aritmética básica (+, -, *, /) entre dos número <strong>de</strong>cimales generados<br />
aleatoriamente. Si la persona que está realizando la prueba (test) respon<strong>de</strong> correctamente, se genera otra<br />
operación; pero si contesta <strong>de</strong> manera incorrecta, la operación se almacena <strong>de</strong> tal forma que pueda ser<br />
planteada <strong>de</strong> nuevo al final <strong>de</strong> la prueba. El siguiente algoritmo muestra los pasos que <strong>de</strong>be seguir el<br />
programa <strong>de</strong> entrenamiento:<br />
1. Leer numOperaciones y el número <strong>de</strong>cimal máximo (maxRango)<br />
2. Generar numOperaciones operaciones y añadirlos a la cola colaOperaciones<br />
3. Para intento = 1 hasta MAX_INTENTOS hacer // Realización <strong>de</strong> la prueba (test)<br />
3.1. Inicializar numFallos = 0<br />
3.2. Para contador = 1 hasta numOperaciones hacer<br />
3.2.1. Mostrar una operación y recoger respuestaUsuario<br />
3.2.2. Si respuestaUsuario == respuestaOperacion<br />
Mostrar mensaje “correcto”<br />
Si no<br />
a. Mostrar mensaje “incorrecto”<br />
b. Añadir la operación a la cola colaOperaciones<br />
c. Incrementar numFallos en 1<br />
3.3. Si numFallos == 0<br />
Mostrar un mensaje <strong>de</strong> felicitación y salir <strong>de</strong>l bucle<br />
Si no<br />
a. Mostrar un mensaje sobre un nuevo intento<br />
b. Hacer numOperaciones = numFallos<br />
4. Si numFallos == 0<br />
Mostrar un mensaje <strong>de</strong> finalización <strong>de</strong>l entrenamiento<br />
Si no<br />
a. Mostrar un mensaje apropiado <strong>de</strong> “<strong>de</strong>masiados intentos”<br />
b. Mientras la colaOperaciones no esté vacía<br />
b.1. Sacar un problema <strong>de</strong>l principio <strong>de</strong> la cola colaOperaciones<br />
b.2. Mostrarlos junto con su respuesta<br />
c. Mostrar el mensaje <strong>de</strong> “necesita mejorar”<br />
Se pi<strong>de</strong>: implementar en C++ el anterior algoritmo para realizar un entrenamiento aritmético, haciendo<br />
uso <strong>de</strong> los TAD <strong>de</strong> la STL <strong>de</strong> C++ que consi<strong>de</strong>re necesarios (por ejemplo, queue).<br />
3. Ejercicio con listas. Las direcciones IP i<strong>de</strong>ntifican unívocamente los or<strong>de</strong>nadores en Internet. Por<br />
ejemplo, la máquina filabres.ual.es tiene la dirección IP 150.214.156.2. Estas direcciones están<br />
formadas por cuatro campos que representan partes específicas <strong>de</strong> Internet, red.subred.subred.máquina,<br />
que el or<strong>de</strong>nador traducirá en una única dirección IP. Esta dirección es un valor <strong>de</strong> 32 bits, pero<br />
normalmente se representa en notación <strong>de</strong>cimal separando los 34 bits en cuatro grupos <strong>de</strong> 8 bits cada<br />
uno, expresando cada campo como un entero <strong>de</strong>cimal (0..255) y separando los campos por un punto.<br />
En el ejemplo anterior: filabres.ual.es ⇔ 150.214.156.2. Supongamos que se establecen conexiones<br />
<strong>de</strong>s<strong>de</strong> una red a través <strong>de</strong> una puerta <strong>de</strong> acceso a otra red, y cada vez que se establece una conexión la<br />
dirección IP <strong>de</strong>l or<strong>de</strong>nador <strong>de</strong>l usuario se almacena en un archivo. Estas direcciones se pue<strong>de</strong>n<br />
recuperar periódicamente para controlar quiénes han utilizado la puerta <strong>de</strong> acceso y cuántas veces lo<br />
han hecho.<br />
Página 9
<strong>Estructuras</strong> <strong>de</strong> <strong>Datos</strong> y <strong>Algoritmos</strong> (<strong>ITIS</strong>). TAD Lineales<br />
Se pi<strong>de</strong>: implementar un programa en C++ que lea estas direcciones IP <strong>de</strong>l archivo y las almacene en<br />
una lista (list <strong>de</strong> la STL <strong>de</strong> C++) enlazada <strong>de</strong> objetos que almacenen una dirección IP y el número <strong>de</strong><br />
veces que dicha dirección aparece en el archivo. Según se lee cada dirección IP <strong>de</strong>l archivo, el<br />
programa <strong>de</strong>be comprobar si ya está en la lista. Si lo está, su contador se incrementa en 1; en caso<br />
contrario, se inserta al final <strong>de</strong> la lista. Una vez que todas las direcciones <strong>de</strong>l archivo han sido leídas, se<br />
mostrará como resultado, en un archivo <strong>de</strong> salida, las distintas direcciones y sus contadores.<br />
Página 10