12.10.2014 Views

Estructuras de Datos y Algoritmos (ITIS)

Estructuras de Datos y Algoritmos (ITIS)

Estructuras de Datos y Algoritmos (ITIS)

SHOW MORE
SHOW LESS

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

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!