Soluciones del Primer Parcial de Programacion 2 – 26/05/2003 Ejercicio 1 Parte a) PROCEDURE DelFront(VAR cn: LDNat); (*Elimina el primer elemento de la Lista con Dos Extemos de Naturales, dando la baja física al nodo que lo contenía. Precondición: la Lista no es vacía.*) VAR aux: PtrNodo; BEGIN IF (cn.ultimo = cn.primero) THEN cn.ultimo := NIL END; aux := cn.primero; cn.primero := cn.primero^.sig; DISPOSE(aux) END DelFront; PROCEDURE DelBack(VAR cn: LDNat); (* Elimina último elemento de la Lista con Dos Extemos de Naturales, dando la baja física al nodo que lo contenía. Precondición: la Lista no es vacía.*) VAR ult, rec: PtrNodo; BEGIN ult:= cn.ultimo; IF (cn.primero = cn.ultimo) THEN cn.primero:= NIL; cn.ultimo:= NIL ELSE rec:= cn.primero; WHILE (rec^.sig # ult) DO rec := rec^.sig END; rec^.sig:= NIL; cn.ultimo:= rec END; DISPOSE(ult) END DelBack; Parte b) PROCEDURE Diferencia(cn1,cn2: LDNat): POINTER TO LDNat; (* Devuelve una Lista con Dos Extremos de Naturales con los elementos que pertenecen a cn1 y no pertenecen a cn2. *) VAR rec1,rec2,rec3,nodo: PtrNodo; ret : POINTER TO LDNat; BEGIN rec1 := cn1.primero; rec2 := cn2.primero; NEW(ret); ret^.primero := NIL; rec3 := NIL; WHILE (rec1 <> NIL) DO WHILE((rec2 <> NIL) AND (rec2^.elem < rec1^.elem)) DO rec2 := rec2^.sig END; IF ((rec2 = NIL) OR (rec1^.elem <> rec2^.elem)) THEN NEW(nodo); nodo^.elem := rec1^.elem; nodo^.sig := NIL; IF (ret^.primero = NIL) THEN ret^.primero := nodo ELSE rec3^.sig := nodo END; rec3 := nodo END; rec1 := rec1^.sig END; ret^.ultimo := rec3; RETURN ret END Diferencia; Otra version: PROCEDURE Diferencia_v2(ld1, ld2: LDNat) :POINTER TO LDNat; VAR ret: POINTER TO LDNat; aux, rec1, rec2: PtrNodo; BEGIN rec1:=ld1.primero; rec2:=ld2.primero; NEW(ret); ret^.primero:=NIL; ret^.ultimo:=NIL; WHILE (rec1<>NIL) AND (rec2<>NIL) DO IF (rec1^.elem < rec2^.elem) THEN NEW(aux); aux^.elem:=rec1^.elem; aux^.sig:=NIL; IF (ret^.ultimo=NIL) THEN ret^.primero:=aux; ELSE ret^.ultimo^.sig:=aux; END; ret^.ultimo:=aux; rec1:=rec1^.sig; ELSIF (rec1^.elem = rec2^.elem) rec1:=rec1^.sig; ELSE rec2:=rec2^.sig; END; END; (*primer while*) WHILE (rec1<>NIL) DO NEW(aux); aux^.elem:=rec1^.elem; aux^.sig:=NIL; IF (ret^.ultimo=NIL) THEN ret^.primero:=aux; ELSE ret^.ultimo^.sig:=aux; END; ret^.ultimo:=aux; rec1:=rec1^.sig; END; (*segundo while*) END Diferencia_v2; Parte c) Una posibilidad es el doble encadenamiento, en ese caso la representación de la Lista de Naturales sería: TYPE PtrNodo = POINTER TO Nodo; Nodo = RECORD elem: CARDINAL; sig, ant: PtrNodo; END; LDNat = RECORD primero: PtrNodo; ultimo: PtrNodo; END; Parte d) PROCEDURE InsBeforeLast (x: CARDINAL; VAR cn: LDNat); (* Inserta un elemento en el penúltimo lugar de la Lista con Dos Extemos de Naturales. Precondición: la Lista no es vacía. *) VAR nuevo: PtrNodo; BEGIN NEW(nuevo); nuevo^.elem:= x; nuevo^.sig:= cn.ultimo; nuevo^.ant:= cn.ultimo^.ant; cn.ultimo^.ant:= nuevo; IF (cn.ultimo = cn.primero) THEN cn.primero:= nuevo ELSE nuevo^.ant^.sig:= nuevo END END InsBeforeLast; Ejercicio 2 Parte a) 1. Retorna verdadero si el árbol es completo y de altura o profundidad k, se puede ver que todas las ramas del árbol son de largo k. 2. Dado que el árbol es binario, completo y de altura k, la cantidad de nodos que tiene es 2k-1. Justificación: Pensando el problema de una forma recursiva, tenemos que la cantidad de hojas de un árbol binario completo de altura k es el doble que las de un árbol de altura k-1 (dado que por cada hoja se tienen dos más). Por lo tanto podríamos definir una función hojas que sería de la forma: hojas(1) = 1 hojas(k) = 2 * hojas(k-1) De esta forma la cantidad de nodos de un árbol de altura k sería igual a la cantidad de nodos del árbol de altura k-1 más sus hojas. Definiendo la función: cant(1) = 1 cant(k) = cant(k-1) + hojas(k) Entonces el resultado de cant(k) para k= 1, 2, 3, etc. es: k=1 cant(1) = 1 k=2 cant(2) = cant(1) + hojas(2) = 1 + hojas(1) * 2 = 1 + 1 * 2 k=3 cant(3) = cant(2) + hojas(3) = 1 + 1*2 + hojas(2)*2 = 1 + 1*2 + 1*2*2 0 k cualquiera (dado que 1=2 ) i k k cant(i) = (i=0..k-1) 2 = (1-2 ) / (1-2) = 2 -1 Parte b) PROCEDURE CopiaAcotada (k: CARDINAL; ab: AB): AB (*Retorne una copia completamente nueva del árbol, de profundidad a lo sumo k, accediendo directamente a la representación *) VAR nuevo: AB; BEGIN IF (k=0) OR (ab=NIL) THEN RETURN NIL ELSE NEW(nuevo); nuevo^.info:= ab^.info; nuevo^.left:= CopiaAcotada(k-1,ab^.left); nuevo^.right:= CopiaAcotada(k-1,ab^.right); RETURN nuevo; END; END CopiaAcotada; Ejercicio 3: Parte a) PROCEDURE Sufijos(l: LCar):LGCar; BEGIN IF Empty(l) THEN RETURN ConsLG(Null(),NullLG()) ELSE RETURN ConsLG(l,Sufijos(Tail(l))) END END Sufijos; Parte b) Una forma de solucionar el problema es insertando al principio de todas las listas generadas por el siguiente paso de la recursión (que se realiza con el resto de la lista) el primer elemento de la lista. Se debe agregar también la lista vacía, ya que la misma es prefijo de cualquier tira. De esta manera, si tenemos la tira “abc”, lo que hacemos es: obtener el resultado de Prefijos de “bc” --> {“”,”b”,”bc”} insertar ‘a’ en todas las listas --> {“a”,”ab”,”abc”} agregar la lista vacía --> {“”,“a”,”ab”,”abc”} PROCEDURE Prefijos(l: LCar):LGCar; BEGIN IF Empty(l) THEN RETURN ConsLG(Null(),NullLG()) ELSE RETURN ConsLG(Null(),Insall(Head(l),Prefijos(Tail(l)))) END END Prefijos; PROCEDURE Insall(x: CARDINAL;lg: LGCar):LGCar; BEGIN IF EmptyLG(lg) THEN RETURN NullLG() ELSE RETURN ConsLG(Cons(x,HeadLG(lg)),Insall(x,TailLG(l))) END END Prefijos; También se puede resolver el problema de una forma análoga a la solución de Sufijos, con la diferencia de que en este caso la recursión se realiza con la lista resultante de quitar el último elemento a la lista original y no el primero. PROCEDURE Prefijos(l: LCar):LGCar; BEGIN IF Empty(l) THEN RETURN ConsLG(Null(),NullLG()) ELSE RETURN ConsLG(l,Prefijos(SacarUltimo(l))) END END Sufijos; PROCEDURE SacarUltimo(l: LCar):LGCar; BEGIN IF (Empty(l)) THEN RETURN l ELSIF (Empty(Tail(l)) THEN RETURN Null() ELSE RETURN Cons(Head(l),SacarUltimo(Tail(l))) END END SacarUltimo;