Documentos de Académico
Documentos de Profesional
Documentos de Cultura
En la tercera parte de la clase de hoy de Informática de 1º del Grado en Matemáticas hemos comentado
las soluciones a los primeros ejercicios de la relación 8 sobre árboles binarios definidos como tipo de dato
algebraico.
-- ---------------------------------------------------------------------
-- Introducción --
-- ---------------------------------------------------------------------
-- ---------------------------------------------------------------------
-- § Librerías auxiliares --
-- ---------------------------------------------------------------------
import Test.QuickCheck
import Control.Monad
-- ---------------------------------------------------------------------
-- Nota. En los siguientes ejercicios se trabajará con los árboles
-- binarios definidos como sigue
-- data Arbol a = H a
-- | N a (Arbol a) (Arbol a)
-- deriving (Show, Eq)
-- Por ejemplo, el árbol
-- 9
-- / \
-- / \
-- 3 7
-- / \
-- 2 4
-- se representa por
-- N 9 (N 3 (H 2) (H 4)) (H 7)
-- ---------------------------------------------------------------------
data Arbol a = H a
| N a (Arbol a) (Arbol a)
deriving (Show, Eq)
-- ---------------------------------------------------------------------
-- Ejercicio 1.1. Definir la función
-- nHojas :: Arbol a -> Int
-- tal que (nHojas x) es el número de hojas del árbol x. Por ejemplo,
-- nHojas (N 9 (N 3 (H 2) (H 4)) (H 7)) == 3
-- ---------------------------------------------------------------------
-- ---------------------------------------------------------------------
-- Ejercicio 1.2. Definir la función
-- nNodos :: Arbol a -> Int
-- tal que (nNodos x) es el número de nodos del árbol x. Por ejemplo,
-- nNodos (N 9 (N 3 (H 2) (H 4)) (H 7)) == 2
-- ---------------------------------------------------------------------
-- ---------------------------------------------------------------------
-- Ejercicio 1.3. Comprobar con QuickCheck que en todo árbol binario el
-- número de sus hojas es igual al número de sus nodos más uno.
-- ---------------------------------------------------------------------
-- La propiedad es
prop_nHojas :: Arbol Int -> Bool
prop_nHojas x =
nHojas x == nNodos x + 1
-- La comprobación es
-- ghci> quickCheck prop_nHojas
-- OK, passed 100 tests.
-- ---------------------------------------------------------------------
-- Ejercicio 2.1. Definir la función
-- profundidad :: Arbol a -> Int
-- tal que (profundidad x) es la profundidad del árbol x. Por ejemplo,
-- profundidad (N 9 (N 3 (H 2) (H 4)) (H 7)) == 2
-- profundidad (N 9 (N 3 (H 2) (N 1 (H 4) (H 5))) (H 7)) == 3
-- profundidad (N 4 (N 5 (H 4) (H 2)) (N 3 (H 7) (H 4))) == 2
-- ---------------------------------------------------------------------
-- ---------------------------------------------------------------------
-- Ejercicio 2.2. Comprobar con QuickCheck que para todo árbol biario
-- x, se tiene que
-- nNodos x <= 2^(profundidad x) - 1
-- ---------------------------------------------------------------------
-- La propiedad es
prop_nNodosProfundidad :: Arbol Int -> Bool
prop_nNodosProfundidad x =
nNodos x <= 2^(profundidad x) - 1
-- La comprobación es
-- ghci> quickCheck prop_nNodosProfundidad
-- OK, passed 100 tests.
-- ---------------------------------------------------------------------
-- Ejercicio 3.1. Definir la función
-- preorden :: Arbol a -> [a]
-- tal que (preorden x) es la lista correspondiente al recorrido
-- preorden del árbol x; es decir, primero visita la raíz del árbol, a
-- continuación recorre el subárbol izquierdo y, finalmente, recorre el
-- subárbol derecho. Por ejemplo,
-- preorden (N 9 (N 3 (H 2) (H 4)) (H 7)) == [9,3,2,4,7]
-- ---------------------------------------------------------------------
-- ---------------------------------------------------------------------
-- Ejercicio 3.2. Comprobar con QuickCheck que la longitud de la lista
-- obtenida recorriendo un árbol en sentido preorden es igual al número
-- de nodos del árbol más el número de hojas.
-- ---------------------------------------------------------------------
-- La propiedad es
prop_length_preorden :: Arbol Int -> Bool
prop_length_preorden x =
length (preorden x) == nNodos x + nHojas x
-- La comprobación es
-- ghci> quickCheck prop_length_preorden
-- OK, passed 100 tests.
-- ---------------------------------------------------------------------
-- Ejercicio 3.3. Definir la función
-- postorden :: Arbol a -> [a]
-- tal que (postorden x) es la lista correspondiente al recorrido
-- postorden del árbol x; es decir, primero recorre el subárbol
-- izquierdo, a continuación el subárbol derecho y, finalmente, la raíz
-- del árbol. Por ejemplo,
-- postorden (N 9 (N 3 (H 2) (H 4)) (H 7)) == [2,4,3,7,9]
-- ---------------------------------------------------------------------
-- ---------------------------------------------------------------------
-- Ejercicio 3.4. Definir, usando un acumulador, la función
-- preordenIt :: Arbol a -> [a]
-- tal que (preordenIt x) es la lista correspondiente al recorrido
-- preorden del árbol x; es decir, primero visita la raíz del árbol, a
-- continuación recorre el subárbol izquierdo y, finalmente, recorre el
-- subárbol derecho. Por ejemplo,
-- preordenIt (N 9 (N 3 (H 2) (H 4)) (H 7)) == [9,3,2,4,7]
--
-- Nota: No usar (++) en la definición
-- ---------------------------------------------------------------------
-- ---------------------------------------------------------------------
-- Ejercicio 3.5. Comprobar con QuickCheck que preordenIt es equivalente
-- a preorden.
-- ---------------------------------------------------------------------
-- La propiedad es
prop_preordenIt :: Arbol Int -> Bool
prop_preordenIt x =
preordenIt x == preorden x
-- La comprobación es
-- ghci> quickCheck prop_preordenIt
-- OK, passed 100 tests.
Etiquetas: Haskell, I1M2017 | Categoría: I1M2017 | Sin comentarios
Árbol binario
Este artículo o sección necesita referencias que aparezcan en una publicación
acreditada.
Este aviso fue puesto el 2 de noviembre de 2011.
En ciencias de la computación, un árbol binario es una estructura de datos en la cual cada nodo
puede tener un hijo izquierdo y un hijo derecho. No pueden tener más de dos hijos (de ahí el
nombre "binario"). Si algún hijo tiene como referencia a null, es decir que no almacena ningún dato,
entonces este es llamado un nodo externo. En el caso contrario el hijo es llamado un nodo interno.
Usos comunes de los árboles binarios son los árboles binarios de búsqueda, los montículos
binarios y Codificación de Huffman.
Índice
[ocultar]
Un árbol binario sencillo de tamaño 9, 3 niveles(Nivel 0 hasta Nivel 3) y altura 4 (altura = máximo nivel + 1),
con un nodo raíz cuyo valor es 2.
En teoría de grafos, se usa la siguiente definición: «Un árbol binario es un grafo conexo, acíclico y
no dirigido tal que el grado de cada vértice no es mayor a 3». De esta forma solo existe un camino
entre un par de nodos.
Un árbol binario con enraizado es como un grafo que tiene uno de sus vértices, llamado raíz, de
grado no mayor a 2. Con la raíz escogida, cada vértice tendrá un único padre, y nunca más de dos
hijos. Si rehusamos el requerimiento de la conectividad, permitiendo múltiples componentes
conectados en el grafo, llamaremos a esta última estructura un bosque'.
Implementación en C[editar]
Un árbol binario puede declararse de varias maneras. Algunas de ellas son:
Estructura con manejo de memoria dinámica, siendo el puntero que apunta al árbol de tipo tArbol:
int árbol[NUMERO_DE_NODOS];
Recorrido en postorden[editar]
En este caso se trata primero el subárbol izquierdo, después el derecho y por último el nodo actual.
Otra forma para entender el recorrido con este método seria seguir el orden: nodo izquierda, nodo
derecha, nodo raíz. En el árbol de la figura el recorrido en postorden sería: 2, 5, 11, 6, 7, 4, 9, 5 y 2.
Recorrido en inorden[editar]
En este caso se trata primero el subárbol izquierdo, después el nodo actual y por último el subárbol
derecho. En un ABB este recorrido daría los valores de clave ordenados de menor a mayor. Otra
forma para entender el recorrido con este método seria seguir el orden: nodo izquierda, nodo raíz,
nodo derecha. En el árbol de la figura el recorrido en inorden sería: 2, 7, 5, 6, 11, 2, 5, 4, 9.
Esquema de implementación:
Preorden
Inorden
Postorden
Para encontrar la raíz es necesario tener el recorrido preorden o postorden, ya que la raíz es el
se tiene el nodo , pero existen 2 nodos con ese valor, el primero y el de en medio. Si el primer
dos es la raíz, entonces no existe ninguna rama del lado izquierdo, en ese caso la siguiente raíz de
Inorden
Postorden
El recorrido inorden, es un recorrido de los árboles binarios en los que se empieza desde el nodo
que se encuentra más a la izquierda de todos, sigue con la raíz y termina con los nodos del lado
derecho, entonces, como en el recorrido inorden ya encontramos la raíz, la parte izquierda
representa el subárbol izquierdo y la parte derecha representa el subárbol derecho.
Preorden Preorden
Inorden Inorden
Postorden Postorden
Se sigue repitiendo el proceso hasta encontrar todos los nodos del árbol, en este punto la siguiente
Inorden
Postorden
índice (partiendo de que la raíz tenga índice cero). Este método tiene como ventajas el tener
almacenados los datos de forma más compacta y por tener una forma más rápida y eficiente de
localizar los datos en particular durante un preoden transversal. Sin embargo, desperdicia mucho
espacio en memoria.
El árbol binario puede ser pensado como el árbol original inclinado hacia los lados, con los bordes
negros izquierdos representando el primer hijo y los azules representado los siguientes hermanos.
Las hojas del árbol de la izquierda serían escritas en Lisp como:
Que se ejecutará en la memoria como el árbol binario de la derecha, sin ningún tipo de letras en
aquellos nodos que tienen un hijo izquierdo.
Véase también[editar]
Árbol (estructura de datos)
Árbol multirrama