Enunciado

Anuncio
Paradigmas de Programación
Práctica 3
Árboles estrictamente binarios
En el módulo Fb_tree, escrito en ocaml, está definido el tipo de dato 'a fb_tree que sirve para representar
“árboles binarios llenos” (full binary trees) con nodos etiquetados con valores de tipo 'a.
Los árboles “binarios llenos” o “estrictamente binarios” o “propiamente binarios” son árboles binarios en
los que de todo nodo, que no sea hoja, “cuelgan dos ramas”. No hay “árboles estrictamente binarios”
vacíos; los más sencillos tienen un sólo nodo que es raíz y hoja a la vez.
El módulo Fb_tree tiene la siguiente interfaz:
type 'a fb_tree
val string_of_tree : ('a -> string) -> 'a fb_tree -> string
exception Branches
val single : 'a -> 'a fb_tree
val comp : 'a -> 'a fb_tree * 'a fb_tree -> 'a fb_tree
val root : 'a fb_tree -> 'a
val branches : 'a fb_tree -> 'a fb_tree * 'a fb_tree
La función string_of_tree sirve para “visualizar como string” el contenido de un árbol. Hay que pasarle
como parámetro una función que permita convertir a strings las etiquetas de los nodos. Esta función se ha
incluido en el módulo sólo a efectos de facilitar la “visualización” de árboles para la realización de
pruebas y no debe utilizarse en los desarrollos que se pedirán a continuación.
La función single construye un árbol-hoja con una etiqueta dada.
La función comp contruye un árbol a partir de una etiqueta para la raíz y de un par de árboles que serán
sus ramas.
La función root devuelve el valor (etiqueta) de la raíz de un árbol.
La función branches devuelve las ramas de un árbol. Si se aplica a un árbol que no tiene rama (un árbolhoja) se activa la excepción Branches.
Se pide definir en ocaml las siguientes funciones:
val is_single : 'a Fb_tree.fb_tree -> bool (* identifica árboles-hoja *)
val l_branch : 'a Fb_tree.fb_tree -> 'a Fb_tree.fb_tree (* rama izquierda *)
val r_branch : 'a Fb_tree.fb_tree -> 'a Fb_tree.fb_tree (* rama derecha *)
val size : 'a Fb_tree.fb_tree -> int (* número de nodos *)
val height : 'a Fb_tree.fb_tree -> int (* altura *)
val preorder : 'a Fb_tree.fb_tree -> 'a list
val postorder : 'a Fb_tree.fb_tree -> 'a list
val inorder : 'a Fb_tree.fb_tree -> 'a list
val leafs : 'a Fb_tree.fb_tree -> 'a list (* lista de hojas *)
val mirror : 'a Fb_tree.fb_tree -> 'a Fb_tree.fb_tree (* imagen especular *)
val treemap : ('a -> 'b) -> 'a Fb_tree.fb_tree -> 'b Fb_tree.fb_tree
(* aplica una función a todos los nodos *)
val is_perfect : 'a Fb_tree.fb_tree -> bool (* un árbol lleno es perfecto si
todas sus hojas están en el mismo nivel *)
val is_complet : 'a Fb_tree.fb_tree -> bool (* un árbol es completo si todo
nivel, excepto quizás el último, está lleno y todos los nodos del último
nivel están lo más a la izquierda posible *)
Para utilizar el módulo Fb_tree puede cargarse el archivo fb_tree.cmo desde el compilador interactivo
ocaml, con la directiva
#load “fb.tree.cmo”;;
El archivo “fb_tree.cmi” debe estar presente en el mismo directorio.
Puede evitarse el tener que calificar los nombre de los valores con el nombre del módulo si se ejecuta la
sentencia
open Fb_tree;;
Para definir la función is_single puede interceptarse la excepción “Branches” utilizando una construcción
“try..with...” Por ejemplo:
let is_single t =
try let _ = branches t in false
with Branches -> true;;
que también puede escribirse:
let is_single t =
try
branches t ; false
with Branches -> true;;
pues <exp1>; <exp2> es una expresión que se evalúa en ocaml evaluando primero la expresión <exp1> y
a continuación la expresión <exp2> y cuyo valor es el de <exp2>.
A continuación se transcriben unos ejemplos de uso de las funciones que hay que definir con los
resultados que deberían dar si las definiciones son correctas.
# let h x = single x;;
val h : 'a -> 'a Fb_tree.fb_tree = <fun>
# let h1 = h 1 and h2 = h 2 and h3 = h 3;;
val h1 : int Fb_tree.fb_tree = <abstr>
val h2 : int Fb_tree.fb_tree = <abstr>
val h3 : int Fb_tree.fb_tree = <abstr>
# let ta = comp 1 (h 2, h 3);;
val ta : int Fb_tree.fb_tree = <abstr>
# let tb = comp 4 (ta, h 5);;
val tb : int Fb_tree.fb_tree = <abstr>
# let tc = comp 4 (ta, ta);;
val tc : int Fb_tree.fb_tree = <abstr>
# let td = comp 4 (h 3, ta);;
val td : int Fb_tree.fb_tree = <abstr>
# let te = comp 6 (tb, h 0);;
val te : int Fb_tree.fb_tree = <abstr>
# let print = string_of_tree string_of_int;;
val print : int Fb_tree.fb_tree -> string = <fun>
# print te;;
- : string = "(6 (4 (1 (2) (3)) (5)) (0))"
# l_branch h1;;
Exception: Fb_tree.Branches.
# r_branch h2;;
Exception: Fb_tree.Branches.
# is_single h3;;
- : bool = true
# is_single ta;;
- : bool = false
# is_single (l_branch ta);;
- : bool = true
# let l = [h1; h2; h3; ta; tb; tc; td; te];;
val l : int Fb_tree.fb_tree list =
[<abstr>; <abstr>; <abstr>; <abstr>; <abstr>; <abstr>; <abstr>; <abstr>]
# List.map root l;;
- : int list = [1; 2; 3; 1; 4; 4; 4; 6]
# List.map size l;;
- : int list = [1; 1; 1; 3; 5; 7; 5; 7]
# List.map height l;;
- : int list = [1; 1; 1; 2; 3; 3; 3; 4]
# preorder tb;;
- : int list = [4; 1; 2; 3; 5]
# preorder te;;
- : int list = [6; 4; 1; 2; 3; 5; 0]
# inorder tb;;
- : int list = [2; 1; 3; 4; 5]
# postorder tb;;
- : int list = [2; 3; 1; 5; 4]
# let et= mirror te;;
val et : int Fb_tree.fb_tree = <abstr>
# preorder et;;
- : int list = [6; 0; 4; 5; 1; 3; 2]
# print et;;
- : string = "(6 (0) (4 (5) (1 (3) (2))))"
# leafs h1;;
- : int list = [1]
# leafs tb;;
- : int list = [2; 3; 5]
# leafs te;;
- : int list = [2; 3; 5; 0]
# print (treemap (function x -> x * x) td);;
- : string = "(16 (9) (1 (4) (9)))"
# List.map is_perfect l;;
- : bool list = [true; true; true; true; false; true; false; false]
# List.map is_complet l;;
- : bool list = [true; true; true; true; true; true; false; false]
Para hacer estas pruebas con mayor comodidad, podrían meterse todos estos ejemplos de uso en un
archivo “test.ml” y todas las definiciones del ejercicio en un archivo “fb_tree_plus.ml” y compilarlo
como un módulo con
ocamlc -c fb_tree_plus.ml
Después se puede arrancar el ocaml, cargar el módulo, abrirlo, y evaluar el archivo de pruebas “test.ml”
con la directiva
#use “test.ml”;;
La salida debería coincidir exactamente con:
val h : 'a -> 'a Fb_tree.fb_tree = <fun>
val h1 : int Fb_tree.fb_tree = <abstr>
val h2 : int Fb_tree.fb_tree = <abstr>
val h3 : int Fb_tree.fb_tree = <abstr>
val ta : int Fb_tree.fb_tree = <abstr>
val tb : int Fb_tree.fb_tree = <abstr>
val tc : int Fb_tree.fb_tree = <abstr>
val td : int Fb_tree.fb_tree = <abstr>
val te : int Fb_tree.fb_tree = <abstr>
val print : int Fb_tree.fb_tree -> string = <fun>
- : string = "(6 (4 (1 (2) (3)) (5)) (0))"
- : bool = true
- : bool = false
- : bool = true
val l : int Fb_tree.fb_tree list =
[<abstr>; <abstr>; <abstr>; <abstr>; <abstr>; <abstr>; <abstr>; <abstr>]
- : int list = [1; 2; 3; 1; 4; 4; 4; 6]
- : int list = [1; 1; 1; 3; 5; 7; 5; 7]
- : int list = [1; 1; 1; 2; 3; 3; 3; 4]
- : int list = [4; 1; 2; 3; 5]
- : int list = [6; 4; 1; 2; 3; 5; 0]
- : int list = [2; 1; 3; 4; 5]
- :
val
- :
- :
- :
- :
- :
- :
- :
- :
int list = [2; 3; 1; 5; 4]
et : int Fb_tree.fb_tree = <abstr>
int list = [6; 0; 4; 5; 1; 3; 2]
string = "(6 (0) (4 (5) (1 (3) (2))))"
int list = [1]
int list = [2; 3; 5]
int list = [2; 3; 5; 0]
string = "(16 (9) (1 (4) (9)))"
bool list = [true; true; true; true; false; true; false; false]
bool list = [true; true; true; true; true; true; false; false]
Descargar