Instituto de Computación. Facultad de Ingeniería. Universidad de la República Solución Parcial de Programación 2 9 de Julio 2004 Ejercicio 1 – Parte a: Para resolver el ejercicio se utiliza el TAD Cola de Naturales, el mismo está definido por las siguientes operaciones: TYPE Queue; (* Procedimiento creador de una cola vacía *) PROCEDURE Create(VAR q : Queue); (* Procedimiento encargado de encolar el elemento t en la cola q *) PROCEDURE Enqueue(t : ARBOL; VAR q : Queue); (* Función que retorna TRUE sii la cola q es vacía *) PROCEDURE Empty(q : Queue):BOOLEAN; (* Función que elimina el primer elemento de la cola q.*) (* Pre: NOT Empty(q); *) PROCEDURE Dequeue(VAR q : Queue); (* Función que retorna el primer elemento de la cola q.*) (* Pre: NOT Empty(q); *) PROCEDURE Front(q : Queue): ARBOL; La solución del problema se presenta a continuación: PROCEDURE Print(t : ARBOL); VAR q : Queue; current : ARBOL; BEGIN IF (t <> NIL) THEN Create(q); Enqueue(t, q); WHILE (NOT Empty(q)) DO current := Front(q); Dequeue(q); REPEAT IF (current^.PrimerHijo <> NIL) DO Enqueue(current^.PrimerHijo); END; WriteCard(current^.Dato); current := current^.SigHermano; UNTIL (current = NIL) END END END Print; Ejercicio 1 – Parte b: Para la solución del ejercicio se utiliza el siguiente procedimiento auxiliar que libera la memoria de la estructura del árbol: (* Procedimiento que elimina la estructura del árbol t *) PROCEDURE Delete(VAR t : ARBOL); BEGIN IF (t <> NIL) THEN Delete(t^.PrimerHijo); Delete(t^.SigHermano); DISPOSE(t); END; END Delete; La solución del ejercicio se presenta a continuación: (* Procedimiento que elimina el subárbol correspondiente al nodo dato *) PROCEDURE DeleteSubTree(VAR t : ARBOL, x : CARDINAL); VAR current : ARBOL; BEGIN IF (t <> NIL) THEN IF (t^.Dato = x) THEN current := t; t := t^.SigHermano; current^.SigHermano := NIL; Delete(current); (* Una alternativa a las dos lineas anteriores es: Delete(current^.PrimerHijo); DISPOSE(current); *) ELSE DeleteSubTree(t^.PrimerHijo, x); DeleteSubTree(t^.SigHermano, x); END; END; END DeleteSubTree; Ejercicio 2 – Parte a: Se presenta una solución dinámica implementada a partir de la utilización de una lista doblemente enlazada con punteros al comienzo y al final. Otra opción hubiera sido realizar una solución estática implementada a partir de la utilización de un arreglo circular, indicando en la estructura el primer elemento o el último elemento y la cantidad. IMPLEMENTATION MODULE Historia; TYPE Lista = POINTER TO Nodo; Nodo = RECORD sig, ant : Lista; elem : INTEGER; END; Historia = POINTER TO Cabezal; Cabezal = RECORD prim, ult : Lista; cant : INTEGER; END; (* Devuelve una historia vacía *) PROCEDURE CrearHistoria () : Historia; VAR hist : Historia BEGIN NEW(hist); hist^.ult := NIL; hist^.prim := NIL; hist^.cant := 0; RETURN hist; END CrearHistoria; (* Inserta en la historia 'hist' el entero 'val'. En caso de que EstaLlenaHistoria(hist) sea TRUE se elimina el elemento más antiguo *) PROCEDURE InsertarHistoria ( val : INTEGER; VAR hist : Historia ); VAR nuevo, aborrar : Lista; BEGIN NEW(nuevo); nuevo^.ant := NIL; nuevo^.elem := val; IF (EstaVaciaHistoria(hist)) THEN nuevo^.sig := NIL; (* el resto de la lista es vacía *) hist^.ult := nuevo; (* es el único elemento, por lo que es el último *) hist^.cant := 1; ELSE IF (EstaLlenaHistoria(hist)) THEN (* hay que quitar el elemento más antiguo *) aborrar := hist^.ult; (* apunto con un auxiliar para luego liberar *) hist^.ult^.ant^.sig := NIL; (* el puntero al siguiente del anteúltimo *) hist^.ult := hist^.ult^.ant; (* debe pasar a ser el último *) DISPOSE(aborrar) (* se libera la memoria del que era último *) ELSE hist^.cant := hist^.cant + 1 (* en caso de que no estuviera lleno se agrega 1 *) END; nuevo^.sig := hist^.prim; (* se pone como siguiente al nuevo la lista anterior *) hist^.prim^.ant := nuevo; END; hist^.prim := nuevo (* ahora el cabezal tiene como comienzo el nuevo nodo *) END InsertarHistoria; (* Devuelve TRUE únicamente si la historia 'hist' no tiene elementos *) PROCEDURE EstaVaciaHistoria ( hist : Historia ) : BOOLEAN; BEGIN RETURN ( hist^.cant = 0 ) END EstaVaciaHistoria; (* Devuelve TRUE únicamente si la historia 'hist' tiene MAXHIST elementos *) PROCEDURE EstaLlenaHistoria ( hist : Historia ) : BOOLEAN; BEGIN RETURN ( hist^.cant = MAXHIST ) END EstaLlenaHistoria; (* Devuelve el último elemento ingresado en la historia 'hist'. Precondicion: NOT EstaVaciaHistoria(hist) *) PROCEDURE ObtenerTopeHistoria ( hist : Historia ) : INTEGER; BEGIN RETURN ( hist^.prim^.elem ) END ObtenerTopeHistoria; (* Elimina el elemento más reciente de la historia 'hist'. Precondicion: NOT EstaVaciaHistoria (hist). *) PROCEDURE QuitarTopeHistoria ( VAR hist : Historia ); VAR aborrar : Lista; BEGIN aborrar := hist^.prim; hist^.prim := hist^.prim^.sig; hist^.cant := hist^.cant - 1; IF (hist^.cant = 0) THEN (* queda vacio => hay que dejarlo tal como CrearHistoria *) hist^.ult := NIL ELSE hist^.prim^.ant := NIL END; DISPOSE(aborrar); END QuitarTopeHistoria; (* Libera toda la memoria reservada por la historia 'hist' *) PROCEDURE DestruirHistoria ( VAR hist : Historia ); BEGIN WHILE (NOT EstaVaciaHistoria(hist)) DO QuitarTopeHistoria(hist) END DISPOSE(hist); END DestruirHistoria; END Historia. Ejercicio 2 – Parte b: MODULE Maquina; CONST MAX = 100; MALCOMANDO = 0; ADICION = 1; SUSTRACCION = 2; DESHACER = 3; REHACER = 4; DESPLEGAR = 5; SALIR = 6; (* Procedimiento auxiliar que vacía una historia. *) PROCEDURE VaciarHistoria ( VAR hist : Historia ); BEGIN IF (NOT EstaVaciaHistoria(hist)) THEN DestruirHistoria(hist); hist := CrearHistoria() END END VaciarHistoria; (* Procedimiento auxiliar que despliega un mensaje de error. *) PROCEDURE DesplegarError ( mensaje : ARRAY OF CHAR ); BEGIN WriteString("ERROR: "); WriteString(mensaje); WriteLn END DesplegarError; (* Procedimiento auxiliar que despliega un valor del tipo integer. *) PROCEDURE Desplegar ( valor : INTEGER ); BEGIN WriteInt(valor,0); WriteLn END Desplegar; (* Procedimiento auxiliar que devuelve un valor del tipo cardinal a partir del comando ingresado. *) PROCEDURE Cualcomando(comando : ARRAY OF CHAR): CARDINAL; BEGIN IF (CompareStr(comando,"adicion") = 0) THEN RETURN ADICION ELSIF (CompareStr(comando,"sustraccion") = 0) THEN RETURN SUSTRACCION ELSIF (CompareStr(comando,"deshacer") = 0) THEN RETURN DESHACER ELSIF (CompareStr(comando,"rehacer") = 0) THEN RETURN REHACER ELSIF (CompareStr(comando,"desplegar") = 0) THEN RETURN DESPLEGAR ELSIF (CompareStr(comando,"salir") = 0) THEN RETURN SALIR ELSE RETURN MALCOMANDO END Cualcomando; (**** Programa Principal ****) VAR opcion : CARDINAL; x, valor : INTEGER; comando : ARRAY [0..20] OF CHAR; D, R : Historia; exito : BOOLEAN; BEGIN x := 0; D := CrearHistoria(); R := CrearHistoria(); Write('>'); Leer_Comando(comando,valor); opcion := Cualcomando(comando); WHILE (opcion # SALIR) DO CASE opcion OF ADICION: IF (ABS(x + valor) <= MAX) THEN InsertarHistoria(x,D); x := x + valor; VaciarHistoria(R) ELSE DesplegarError("Excede el intervalo") END | SUSTRACCION: IF (ABS(x - valor) <= MAX) THEN InsertarHistoria(x,D); x := x - valor; VaciarHistoria(R) ELSE DesplegarError("Excede el intervalo") END | DESHACER: IF (NOT EstaVaciaHistoria(D)) THEN InsertarHistoria(x,R); x := ObtenerTopeHistoria(D); QuitarTopeHistoria(D) ELSE DesplegarError("Historia Vacia") END | REHACER: IF (NOT EstaVaciaHistoria(R)) THEN InsertarHistoria(x,D); x := ObtenerTopeHistoria(R); QuitarTopeHistoria(R) ELSE DesplegarError("Historia Vacia") END | DESPLEGAR : Desplegar(x) END; Write('>'); Leer_Comando(comando,valor); opcion := Cualcomando(comando); END END Maquina.