dit UPM Depto. Ingeniería de Sistemas Telemáticos Universidad Politécnica de Madrid ETSI Telecomunicación Laboratorio de Programación 19 de Junio de 2002 Soluciones EJERCICIO 1 (UNA PÁGINA: UNA HOJA POR UNA CARA) Se desea añadir un iterador específico para la clase SerieGeometrica. Para ello, se define la clase IteraSerieGeometrica, que implementa la interface Iterator. El método next() deberá calcular cada elemento de la serie como el producto del valor anterior y la constante multiplicativa de la serie. Conteste a los siguientes apartados: 1.1. Escriba la declaración de las variables de instancia necesarias en IteraSerieGeometrica. 1.2. Escriba el constructor de IteraSerieGeometrica que asigna los valores iniciales a las variables de instancia del apartado anterior. 1.3. Escriba el método next(). 1.4. Describa brevemente qué otras clases o interfaces modificaría, y cómo, para que el resultado del siguiente método fuera true: boolean pruebaIteraSerieGeometrica () { Serie s= new SerieGeometrica (1, 2); return (s.iterator() instanceof IteraSerieGeometrica); } 1.1 int sig; // valor siguiente de la serie geometrica int factor; // constante multiplicativa de la serie geometrica 1.2 public IteraSerieGeometrica (int inicial, int _factor){ sig= inicial; factor= _factor; } 1.3 public Object next (){ Integer r= new Integer (sig); // valor que se va a devolver sig *= factor; // se deja listo sig para la próxima vez return r; } 1.4 Se debe redefinir el método iterator en la clase SerieGeometrica, de manera que devuelva un objeto de la nueva clase IteraSerieGeometrica. En SerieGeometrica.java se debería incluir el siguiente método: public Iterator iterator () { return new IteraSerieGeometrica (s1, factor); } 1 EJERCICIO 2 (DOS PÁGINAS: UNA HOJA POR AMBAS CARAS) Queremos modificar el simulador de la bancada de modems para introducir la siguiente funcionalidad: Cada vez que la simulación detecte el rechazo de n llamadas seguidas el simulador introducirá el estado actual de la lista de eventos en una estructura de datos con disciplina de cola, vaciará la lista de eventos y seguirá la simulación. 2.1. Diseñe la estructura de datos “cola de lista de eventos” 2.2. Modifique ModemSim para que: a. admita un nuevo parámetro n: número de llamadas rechazadas que disparan la nueva funcionalidad b. detecte el rechazo e introduzca la lista de eventos en la cola c. imprima al final de la simulación la cola de listas de eventos, con el formato: Log 1 Evento 1 Evento 2 ... Evento n Log 2 Evento 1 Evento 2 ... Evento n ... Log n Evento 1 Evento 2 ... Evento n 2.1 Ver apuntes para diseño de una cola con nodos lista de eventos. Esta clase es ColaListaEventos. 2.2 Añadir una constante en MiModemSim, número máximo de llamadas consecutivas static final int NUM_RECHAZOS = 3; En runSim añadir una variable que cuente los rechazos seguidos y crear una cola de lista de eventos int rechazosSeguidos = 0; ColaListaEventos colaListaEventos = new ColaListaEventos(); Al comparar los modems libres, cuando se acepta una conexión, poner a cero rechazosSeguidos (sólo se tienen en cuenta llamadas consecutivas). Si la llamada se rechaza, incrementar rechazsosSeguidos y comprobar si llegamos a NUM_RECHAZOS. Si llegamos, introducir el estado en ColaListaEventos, vaciar la lista de eventos y reinciar rechazosSeguidos. Al final el método runSim al salir del bucle while añadimos que se imprima la lista de eventos tras la simulación. 2 if (freeModems > 0) { freeModems--; ... rechazosSeguidos = 0; } else { System.out.println(“pero recibe señal de ocupado”); rechazosSeguidos++; if (rechazosSeguidos >= NUM_RECHAZOS) { colaListaEventos.add(eventSet); eventSet.makeEmpty(); rechazosSeguidos = 0; } nextCall(freqOfCalls); } System.out.println(colaListaEventos.printListaEventos()); EJERCICIO 3 (DOS PÁGINAS: UNA HOJA POR AMBAS CARAS) En la práctica del laboratorio se ha supuesto en todo momento que los nodos son capaces de gestionar todo el flujo que haga falta, sin más limitación que la capacidad de los enlaces. Vamos a alterar este supuesto: los nodos pueden tener un límite en el flujo que circula por ellos flujo entrante = flujo saliente = F1 (ver nota al pie) F≤L Donde el límite L puede establecerse de forma independiente para cada nodo. 3.1. Indique cómo modificaría el fichero de datos para poder imponer un límite a algunos nodos (no necesariamente a todos). 3.2. Indique qué pruebas debería desarrollar en FicheroDatosTest.java para probar esta nueva información. No escriba las pruebas; sólo indique qué pruebas haría. 3.3. Modifique el código de Datos.java. 3.4. Modifique el código de MisPosibilidades.java: Indique qué se debería modificar en cada uno de los métodos combinaciones(),validos() y busca() (puede que alguno de ellos no requiera modificación alguna) 3.5. Indique qué pruebas debería desarrollar en PosibilidadesTest.java para probar el funcionamiento del algoritmo sobre redes con nodos de capacidad limitada. No escriba las pruebas; sólo indique qué pruebas haría. 3.1 Hay que introducir un nuevo tipo de línea en el fichero de entrada que incluya el número del nodo al que vamos a aplicar el límite el límite con las condiciones siguientes el nodo debe estar dentro de los existentes 1 Esta ecuación es cierta para todos los nodos, excepto el nodo origen (que carece de flujo entrante) y el nodo destino (que carece de flujo saliente). 3 el límite debe ser mayor o igual a cero, L ≥ 0 Para distinguir esta línea de las ya existentes podemos, por ejemplo, diferenciarla insertando un primer caracter especial: por ejemplo un asterisco, de forma que *24 100 indica que el nodo 24 tiene un límite de 100 en el flujo asumible. 3.2 Hay que probar que 1. se carga el límite 2. se detecta un nodo incorrecto (negativo o más allá del número total de nodos 3. se detecta un flujo negativo 3.3 Hay que preparar una estructura de datos para almacenar el límite, si existe. Como tiene que ser positivo, codificaremos con el valor –1 aquellos nodos que no tienen límite, que será lo normal salvo que el fichero de datos lo imponga. private int limite[]; // inicialización public Datos (int n, ...) { ... limite= new int[n]; for (int i= 0; i < n; i++) limite[n]= -1; } // carga de valores public void limite (int nodo, int max) { limite[nodo]= max; } public int limite (int nodo) { return limite[nodo]; } 3.4 combinaciones() no hay que modificar nada validos() hay que aceptar sólo aquellas asignaciones de flujo que respeten el valor máximo si lo hubiera ... boolean ok= n == origen || n == destino || f.flujo(n) == 0; int lim= datos.limite(n); if (lim >= 0) { int entrante= 0; for (int i= 0; i < tamanno; i++) if (f.flujo(i, n) > 0) entrante++; ok&= entrante <= lim; } if (ok) valen.add(f); 4 busca() No hay que modificar nada. 3.5 Se toma un caso de prueba cuya solución implique que por un nodo N pasan X datos, siendo X mayor que cero. A continuación se preparan dos casos de prueba: 1. se limita el tráfico por N a 0 y se observa que cambia la solución, respetando el límite 2. se limita el tráfico por N a algún valor entre 0 y X y se observa que cambia la solución, respetando el límite 3. se limita el tráfico por N al valor X y se observa que no cambia la solución 4. se limita el tráfico por N a un valor superior a X y se observa que no cambia la solución 5