Está en la página 1de 20

Árboles Binarios

Un árbol binario es un árbol tal que


cada nodo tiene como máximo dos
subárboles.
Los árboles binarios suelen ser
utilizados como contenedores de
datos, por lo que será importante
definir una función que compruebe si
un dato pertenece a un árbol.

• data ÁrbolB a = VacíoB | NodoB (ÁrbolB a) a


(ÁrbolB a) deriving Show
• perteneceB :: Eq a => a -> ÁrbolB a -> Bool
• perteneceB x VacíoB = False
• perteneceB x (NodoB i r d)
• | x == r = True
• | otherwise = perteneceB x i ||
perteneceB x d
Árbol binario de búsqueda
• En cualquier nodo los elementos del subárbol
izquierdo son menores y los elementos del
subárbol derecho son mayores.
50

30 60

25 35 80
Árbol binario de búsqueda en Haskell
• a2 :: ÁrbolB Intu
• a2 = NodoB (NodoB (hojaB 25)
• 30
• (hojaB 35))
• 50
• (NodoB VacíoB
• 60
• (hojaB 80))
• where
• hojaB x = NodoB VacíoB x VacíoB
¿Un árbol binario es de búsqueda?
• todosÁrbolB :: (a -> Bool) -> ÁrbolB a -> Bool
• todosÁrbolB p VacíoB = True
• todosÁrbolB p (NodoB i r d) = p r &&
• todosÁrbolB p i && todosÁrbolB p d
• ---------------------------------------------------------------
• esÁrbolBB :: Ord a => ÁrbolB a -> Bool
• esÁrbolBB VacíoB = True
• esÁrbolBB (NodoB i r d) = todosÁrbolB (< r) i &&
• todosÁrbolB (>r) d &&
• esÁrbolBB i &&
• esÁrbolBB d
• Si el dato que buscamos no es la raíz sólo hay
que buscar en uno de los subárboles de modo
que como máximo se realizan tantas
comparaciones como profundidad tenga el
árbol.
• Dado que es posible almacenar datos
en un árbol de profundidad n, el algoritmo es
de orden lg n.
• La ganancia es significativa, frente a utilizar
una lista, ya que con esta estructura puede ser
necesario realizar n comparaciones
Busca un elemento, en un árbol
binario de búsqueda
• perteneceBB :: Ord a => a -> ÁrbolB a -> Bool
• perteneceBB x VacíoB = False
• perteneceBB x (NodoB i r d)
• | x == r = True
• | x < r = perteneceBB x i
• | otherwise = perteneceBB x d
Inserta un elemento, en un árbol
binario de búsqueda

• insertarBB :: Ord a => a -> ÁrbolB a -> ÁrbolB a


• insertarBB x VacíoB = NodoB VacíoB x VacíoB
• insertarBB x (NodoB i r d)
• | x <= r = NodoB (insertarBB x i) r d
• | otherwise = NodoB i r (insertarBB x d)
Eliminar un elemento en un árbol
binario de búsqueda
• La eliminación es más complicada, ya que si el
nodo a eliminar tiene dos subárboles no se puede
dejar un hueco en su lugar. Colocaremos el mayor
elemento del subárbol izquierdo del nodo a
eliminar.

• esVacíoB :: ÁrbolB a -> Bool


• esVacíoB VacíoB = True
• esVacíoB _ = False
eliminarBB :: Ord a => a -> ÁrbolB a -> ÁrbolB a
eliminarBB x VacíoB = VacíoB
eliminarBB x (NodoB i r d)
| x < r = NodoB (eliminarBB x i) r d
| x > r = NodoB i r (eliminarBB x d)
| esVacíoB i = d
| esVacíoB d = i
| otherwise = NodoB i' mi d
where
(mi, i') = tomaMaxBB i
tomaMaxBB (NodoB i r VacíoB) = (r, i)
tomaMaxBB (NodoB i r d) = (m, NodoB i r d')
where
(m, d') = tomaMaxBB d
Recorrido en orden en un árbol binario

• El recorrido en orden de un árbol binario dará


como resultado una lista con los datos de un
árbol de modo que primero se recorre el
subárbol izquierdo, luego la raíz y por último
el subárbol derecho.
Recorrido inOrden, en Haskell

inOrden :: ÁrbolB a -> [a]


inOrden VacíoB = []
inOrden (NodoB i r d) =
inOrden i ++ (r : inOrden d)
Problema
• Hacer programas en Haskell que realicen
recorridos en preorden (r,i,d) y en postorden
(i,d,r)
• Ejecutar estos programas con árboles tal que
tengan como salida sus nombres.
La complejidad de inOrden es
cuadrática, que es mejorado por:
• inOrden' :: ÁrbolB a -> [a]
• inOrden' x= aux x []
• where
• aux :: ÁrbolB a -> [a] -> [a]
• aux VacíoB xs = xs
• aux (NodoB i r d) xs = aux i (r : aux d xs)
Si se realiza una visita en inOrden a un
árbol binario de búsqueda se obtiene
una lista ordenada

• listaAÁrbolBB :: Ord a => [a] -> ÁrbolB a


• listaAÁrbolBB = foldr insertarBB VacíoB

• treeSort :: Ord a => [a] -> [a]
• treeSort = inOrden . listaAÁrbolBB
Al construir un árbol binario de
búsqueda con una lista de elementos
ordenados se obtiene un árbol
degenerado, con lo que se pierde la
eficiencia al acceder a los elementos
de un árbol
• treeSort [2,3,1,5,4,7,8]
• listaAÁrbolBB [2,6,4,7,8,5,9]
• listaAÁrbolBB [1,2,3,4,5]
Cuando la lista esté ordenada
podemos obtener un árbol no
degenerado conla función :
• lOrdAÁrbolBB :: Ord a => [a] -> ÁrbolB a
• lOrdAÁrbolBB [] = VacíoB
• lOrdAÁrbolBB xs = NodoB (lOrdAÁrbolBB ys) z
(lOrdAÁrbolBB zs)
• where
• (ys, z:zs) = partir xs
• partir xs = splitAt (length xs `div` 2) xs
La función splitAt es utilizada para
partir la lista en dos mitades y así
distribuir la mitad de los elementos en
cada subárbol

• let xs = [1..6] in splitAt (length xs `div` 2) xs

• lOrdAÁrbolBB [1..8]

También podría gustarte