Inserción en árboles binarios de búsqueda
Un árbol binario de búsqueda (ABB) es un árbol binario tal que el cada nodo es mayor que los valores de su subárbol izquierdo y menor que los valores de su subárbol derecho y, además, ambos subárboles son árboles binarios de búsqueda. Por ejemplo, al almacenar los valores de [8,4,2,6,3] en un ABB se puede obtener el siguiente ABB:
3 / \ / \ 2 6 / \ 4 8
Los ABB se pueden representar como tipo de dato algebraico:
data ABB = V | N Int ABB ABB deriving (Eq, Show)
Por ejemplo, la definición del ABB anteriore es
ej :: ABB ej = N 3 (N 2 V V) (N 6 (N 4 V V) (N 8 V V))
Definir la función
inserta :: Int -> ABB -> ABB
tal que (inserta v a)
es el árbol obtenido añadiendo el valor v
al ABB a
, si no es uno de sus valores. Por ejemplo,
λ> inserta 5 ej N 3 (N 2 V V) (N 6 (N 4 V (N 5 V V)) (N 8 V V)) λ> inserta 1 ej N 3 (N 2 (N 1 V V) V) (N 6 (N 4 V V) (N 8 V V)) λ> inserta 2 ej N 3 (N 2 V V) (N 6 (N 4 V V) (N 8 V V))
Comprobar con QuickCheck que al insertar un valor en un ABB se obtiene otro ABB.
Soluciones
{-# LANGUAGE FlexibleInstances #-} import Test.Hspec (Spec, hspec, it, shouldBe) import Test.QuickCheck data ABB a = V | N a (ABB a) (ABB a) deriving (Show, Eq) ej :: ABB Int ej = N 3 (N 2 V V) (N 6 (N 4 V V) (N 8 V V)) inserta :: Ord a => a -> ABB a -> ABB a inserta v' V = N v' V V inserta v' (N v i d) | v' == v = N v i d | v' < v = N v (inserta v' i) d | otherwise = N v i (inserta v' d) -- Verificación -- ============ verifica :: IO () verifica = hspec spec spec :: Spec spec = do it "e1" $ inserta 5 ej `shouldBe` N 3 (N 2 V V) (N 6 (N 4 V (N 5 V V)) (N 8 V V)) it "e2" $ inserta 1 ej `shouldBe` N 3 (N 2 (N 1 V V) V) (N 6 (N 4 V V) (N 8 V V)) it "e3" $ inserta 2 ej `shouldBe` N 3 (N 2 V V) (N 6 (N 4 V V) (N 8 V V)) -- La verificación es -- λ> verifica -- 3 examples, 0 failures -- Comprobación de la propiedad -- ============================ -- (elementos a) es la lista de los valores de los nodos del ABB a en el -- recorrido inorden. Por ejemplo, -- elementos ej == [2,3,4,6,8] elementos :: ABB a -> [a] elementos V = [] elementos (N v i d) = elementos i ++ [v] ++ elementos d -- (menorTodos v a) se verifica si v es menor que todos los elementos -- del ABB a. Por ejemplo, -- menorTodos 1 ej == True -- menorTodos 2 ej == False menorTodos :: Ord a => a -> ABB a -> Bool menorTodos _ V = True menorTodos v a = v < minimum (elementos a) -- (mayorTodos v a) se verifica si v es mayor que todos los elementos -- del ABB a. Por ejemplo, -- mayorTodos 9 ej == True -- mayorTodos 8 ej == False mayorTodos :: Ord a => a -> ABB a -> Bool mayorTodos _ V = True mayorTodos v a = v > maximum (elementos a) -- (esABB a) se verifica si a es un ABB correcto. Por ejemplo, -- esABB ej == True esABB :: Ord a => ABB a -> Bool esABB V = True esABB (N v i d) = mayorTodos v i && menorTodos v d && esABB i && esABB d -- vacio es el árbol binario de búsqueda vacío. vacio :: ABB a vacio = V -- genABB es un generador de árboles binarios de búsqueda. Por ejemplo, -- λ> generate genABB -- N (-23) (N (-29) V V) (N (-3) V (N 6 V V)) -- λ> generate genABB -- N (-24) V V genABB :: Gen (ABB Int) genABB = do xs <- listOf arbitrary return (foldr inserta vacio xs) instance Arbitrary (ABB Int) where arbitrary = genABB -- La propiedad es prop_inserta :: Int -> ABB Int -> Bool prop_inserta v a = esABB (inserta v a) -- La comprobación es -- λ> quickCheck prop_inserta -- +++ OK, passed 100 tests.