SOLUCIÓN EXAMEN DE ALGORITMOS Y ESTRUCTURAS DE DATOS II (AD2). 9 de Septiembre de 2002. Convocatoria Extraordinaria. Duración: 3 horas Ejercicio 1 (prácticas). Puntuación: 2 puntos. Los apellidos terminados en "EZ" provienen de los Visigodos, el pueblo germánico que, con la decadencia del Imperio Romano, se estableció en la Península Ibérica y fundó aquí un Reino. "EZ" significa "Hijo de", y equivale a las terminaciones "-son" de los apellidos de origen nórdico (Anderson, Johnson), "-vitch" o "-ievna" de los patronímicos rusos (Nikolaievitch), etc... Así, el origen remoto de un "González" está en alguien que fue llamado ''Hijo de Gonzalo'' (González); "Álvarez" en ''Hijo de Álvaro'' (Álvar-ez); etc... De esta manera, toda una serie de apellidos hispánicos muy frecuentes tiene su origen, en la Edad Media, en el nombre propio del padre [www.surnames.org/apellido.htm]. Se dispone de una función sufijoEz que comprueba si una palabra tiene “ez” como sufijo, cuya cabecera es la siguiente function sufijoEz (var p: palabra): boolean; Ejemplo: sufijoEz (‘González’) = true y sufijoEz (‘Marqués’) = false. Una vez comprobado que una palabra tiene “ez” como sufijo, diseñar eficientemente en Pascal un procedimiento HijodeEz que sustituye el sufijo ez por el sufijo o y añade como prefijo su traducción en castellano Hijode. Ejemplo: la palabra González se cambiaría a HijodeGonzalo. Utilícese la siguiente definición de tipos para completar en el recuadro el diseño en Pascal del procedimiento. type palabra = ^nodoPal; nodoPal = record letra: char; sig: palabra end; { sufijoEz(p) = true } procedure HijodeEz (var p: palabra); var ant_aux, aux, nuevo: palabra; begin ant_aux:= nil; i:integer; aux:= p; (* Con este bucle ant_aux y aux apuntan al penúltimo y último nodo de la palabra, respectivamente. Es decir, al sufijo ‘ez’ *) while (aux^.sig <> nil) do begin ant_aux:= aux; aux:= aux^.sig end; (* Se cambia la ‘e’ por la ‘o’ y se borra la ‘z’ *) ant_aux^.letra := ‘o’; ant_aux^.sig := nil; dispose(aux); (* Se crean y añaden en cabeza los nodos que forman el prefijo ‘Hijode’ *) for i:= 1 to 6 do begin new(nuevo); case i of 1: nuevo^.letra:= ‘e’; 2: nuevo^.letra:= ‘d’; 3: nuevo^.letra:= ‘o’; 4: nuevo^.letra:= ‘j’; 5: nuevo^.letra:= ‘i’; 6: nuevo^.letra:= ‘H’ end; nuevo^.sig := p; p := nuevo end; end; Ejercicio 2 (prácticas). Puntuación: 1.25 puntos. La función recursiva campanadas averigua cuántas campanadas da un reloj de pared desde una hora especificada hasta el final del día. Por ejemplo, si son las 20 horas, el reloj dará 50 campanadas ( 50 = 8 + 9 + 10 + 11 + 12 ). const hfin = 24; hmitad = 12; function campanadas (hora: integer): integer; var ding_dong: integer; begin if (hora<=hfin) then begin if (hora<=hmitad) then ding_dong := hora else ding_dong := hora – hmitad; campanadas := ding_dong + campanadas (hora+1) end else campanadas := 0 end; Si la llamada inicial a la función campanadas desde el programa principal es nc := campanadas(h); siendo nc y h variables globales de tipo integer e inicialmente h = 20, elegir de entre los tres registros de activación que se muestran en la figura, el que se apila en primer lugar (en caso de respuesta incorrecta se resta 0.25) y rellenar parte de los registros de las columnas de la pila. Cada columna representa la secuencia de registro(s) de activación cada vez que se detiene la ejecución de la función debido a su punto de ruptura. hora = 20 ding_dong = ? campanadas = ? 24 ? ? hora ding_dong campanadas 20 ? 23 ? ? 23 11 ? 22 ? 22 10 22 10 21 ? ? 21 9 ? 21 9 ? 21 9 ? 20 8 20 8 20 8 20 8 Ejercicio 3 (prácticas). Puntuación: 0.75 puntos (en caso de respuesta incorrecta se resta 0.25). En el siguiente fragmento de código, se ha medido el tiempo consumido por el procedimiento NumerosRomanos que escribe la pronunciación en latín de los primeros num números. Ejemplo: NumerosRomanos(4), escribe utilizando caracteres latinos la pronunciación de los números: 1 (unus), 2 (duo), 3 (tres) y 4 (quattuor). … var n, t1, t2: integer; … procedure NumerosRomanos (num: integer); var i: integer; begin i := 1; while i≤num do begin case i of 1: writeln(‘unus’); 2: writeln(‘duo’); 3: writeln(‘tres’); 4: writeln(‘quattuor’); … end; i:=i+1 end end; begin {programa principal} {línea 1} writeln (‘Talla Tiempo’); {2} n:=2; {3} while n<=100 do begin {4} t1:= clock; {5} NumerosRomanos (n*5); {6} t2:= clock-t1; {7} n := n + 2; {8} writeln (n*5:5, t2:7:2); {9} end; end. {programa principal} Los resultados obtenidos han sido: Talla 10 20 . . 500 Tiempo 0 0 . . 0 Se quiere modificar adecuadamente el código anterior para evaluar correctamente el tiempo consumido por el procedimiento NumerosRomanos. Hay que modificar: for k:=1 to rep do NumerosRomanos(n*5); la línea 5: writeln(n*5:5, t2/rep:7:2); la línea 7: con k variable entera y rep = número de repeticiones necesarias para obtener tiempos significativos n := n + 2 y la línea 8: Ejercicio 4 (teoría). Puntuación: 1 punto. Considérese el procedimiento NumerosRomanos del ejercicio anterior. I) Puntuación: 0.25 puntos. Determinar la talla = num (valor del número) II) Puntuación: 0.75 puntos (en caso de respuesta incorrecta se resta 0.25). La complejidad temporal es: t(talla) ∈Θ(talla) Ejercicio 5 (teoría). Puntuación: 1 punto. Determinar la talla del algoritmo campanadas del ejercicio 2 y, en función de la misma, plantear las relaciones de recurrencia correspondientes. Elegir de entre las complejidades indicadas la que corresponde a campanadas. Talla: m = hfin – hora + 1 K1 si m = 0 (hora > 24) K2 + t(m-1) si m > 0 (hora ≤ 24) Relaciones de recurrencia: t(m) = Coste: lineal Ejercicio 6 (teoría). Puntuación: 1.5 puntos. El siguiente procedimiento alachina, dada una palabra en español la traduce a espa-chino, es decir, pronunciada en español a lo chino. Por ejemplo: las palabras “algoritmo” y “morro” serían en espa-chino “algolitmo” y “molo”, respectivamente. type palabra = ^nodoPal; nodoPal = record letra: char; sig: palabra end; { p tiene al menos 1 símbolo } procedure alachina (var p: palabra); var aux, ant_aux: palabra; begin aux:= p^.sig; ant_aux:= p; while (aux<>nil) do begin if ant_aux^.letra = ‘r’ then begin ant_aux^.letra:= ‘l’; if aux^.letra = ‘r’ then begin ant_aux^.sig := aux^.sig; dispose(aux); aux:=ant_aux^.sig end; end; ant_aux := aux; aux:= aux^.sig end; if ant_aux^.letra = ‘r’ then ant_aux^.letra:= ‘l’; end; Estudiar el coste del procedimiento alachina en función de la talla del problema. I) Puntuación: 0.75 puntos. Talla = número de símbolos de la palabra p II) Puntuación: 0.75 puntos (por cada respuesta incorrecta se resta 0.25). no hay instancias significativas y el coste es: lineal con la talla del problema Ejercicio 7 (teoría). Puntuación: 0.75 puntos (en caso de respuesta incorrecta se resta 0.25). procedure alachina (p: palabra); Si la cabecera del procedimiento anterior fuera Tras la invocación, desde el algoritmo principal, al procedimiento alachina(pesp); siendo pesp una variable global de tipo palabra: pesp pasaría a ser la correspondiente palabra en espa-chino Ejercicio 8 (teoría). Puntuación: 1.75 puntos (1.25 en caso de diseño iterativo). Dada una lista (con punto de interés) l de palabras en español, diseñar un procedimiento palabraschinas que cambie las palabras de la lista por su traducción a espa-chino, haciendo uso únicamente de: a) las operaciones del TAD lista con punto de interés que se han estudiado en la teoría procedimiento creal (ssal l: lista[palabra]); procedimiento inserta (ent/sal l: lista[palabra]; ent p:palabra); procedimiento suprime (ent/sal l:lista[palabra]); función recupera (l: lista[palabra]) devuelve palabra; b) y del procedimiento alachina del ejercicio 6, cuya procedimiento principio (ent/sal l: lista[palabra]); procedimiento fin (ent/sal l: lista[palabra]); procedimiento siguiente (ent/sal l: lista[palabra]); función esvacial (l: lista[palabra]) devuelve lógico; función esfinl (l: lista[palabra]) devuelve lógico; cabecera es: procedimiento alachina (ent/sal p: palabra); Por ejemplo: La lista l = { “algoritmo”, “estructuras”, “dos”, “tres”, “cuatro”, “cinco”, “morro” } de palabras en español es en espa-chino l = { “algolitmo”, “estluctulas”, “dos”, “tles”, “cuatlo”, “cinco”, “molo” }. procedimiento palabraschinas (ent/sal l: lista[palabra]); (* VERSIÓN ITERATIVA *) var p: palabra; fvar; principio(l); mientras not esfinl(l) hacer p := recupera(l); alachina(p); inserta(l, p); suprime(l) fmientras; fprocedimiento; (* VERSIÓN RECURSIVA *) var p: palabra; fvar; si not esfinl(l) entonces p := recupera(l); alachina(p); inserta(l, p); suprime(l); palabraschinas(l) fsi fprocedimiento; Llamada inicial para el procedimiento recursivo: principio( li ); palabraschinas( li ); siendo li una variable global declarada como sigue: li: lista[palabra];