-- | -- Module : Monticulo -- Description : TAD de los montículos. -- License : Creative Commons -- Maintainer : José A. Alonso -- -- TAD (tipo abstracto de datos) de los montículos. -- -- Este módulo contiene el código del TAD de los montículos -- estudiado en el <http://bit.ly/1F5Sl5B tema 20> del curso. -- -- Un montículo es un árbol binario en el que los valores de cada nodo es -- menor o igual que los valores de sus hijos. Por ejemplo, -- 1 -- / \ -- / \ -- 2 6 -- / \ / \ -- 3 8 9 7 -- es un montículo, pero -- 1 -- / \ -- / \ -- 3 6 -- / \ / \ -- 4 2 9 7 -- no lo es. module I1M.Monticulo (Monticulo, vacio, -- Ord a => Monticulo a inserta, -- Ord a => a -> Monticulo a -> Monticulo a menor, -- Ord a => Monticulo a -> a resto, -- Ord a => Monticulo a -> Monticulo a esVacio, -- Ord a => Monticulo a -> Bool valido -- Ord a => Monticulo a -> Bool ) where import Data.List (sort) -- | El tipo de dato de los montículos. data Monticulo a = Vacio | M a Int (Monticulo a) (Monticulo a) deriving Show -- Ejemplos de montículos -- ghci> m1 -- M 1 2 (M 4 1 (M 8 1 Vacio Vacio) Vacio) (M 6 1 Vacio Vacio) -- ghci> m2 -- M 5 1 (M 7 1 Vacio Vacio) Vacio -- ghci> m3 -- M 1 2 -- (M 5 2 -- (M 7 1 Vacio Vacio) -- (M 6 1 Vacio Vacio)) -- (M 4 1 -- (M 8 1 Vacio Vacio) -- Vacio) -- Gráficamente -- m1 m2 m3 -- -- (1,2) -- (1,2) (5,1) / \ -- / \ / / \ -- (4,1) (6,1) (7,1) (5,2) (4,1) -- / / \ / -- (8,1) (7,1) (6,1) (8,1) m1, m1', m2, m3 :: Monticulo Int m1 = foldr inserta vacio [6,1,4,8] m1' = foldr inserta vacio [6,8,4,1] m2 = foldr inserta vacio [7,5] m3 = mezcla m1 m2 -- | vacio es el montículo vacío. vacio :: Ord a => Monticulo a vacio = Vacio -- | (rango m) es el rango del montículo m; es decir, la menor distancia -- a un montículo vacío. Por ejemplo, -- -- > rango (foldr inserta vacio [6,1,4,8]) == 2 -- > rango (foldr inserta vacio [7,5]) == 1 rango :: Ord a => Monticulo a -> Int rango Vacio = 0 rango (M _ r _ _) = r -- | (creaM x a b) es el montículo creado a partir del elemento x y los -- montículos a y b. Se supone que x es menor o igual que el mínimo de -- a y de b. Por ejemplo, -- -- > ghci> creaM 0 (foldr inserta vacio [6,1,4,8]) (foldr inserta vacio [7,5]) -- > M 0 2 (M 1 2 (M 4 1 (M 8 1 Vacio Vacio) Vacio) (M 6 1 Vacio Vacio)) -- > (M 5 1 (M 7 1 Vacio Vacio) Vacio) -- > ghci> creaM 0 (foldr inserta vacio [7,5]) (foldr inserta vacio [6,1,4,8]) -- > M 0 2 (M 1 2 (M 4 1 (M 8 1 Vacio Vacio) Vacio) (M 6 1 Vacio Vacio)) -- > (M 5 1 (M 7 1 Vacio Vacio) Vacio) creaM :: Ord a => a -> Monticulo a -> Monticulo a -> Monticulo a creaM x a b | rango a >= rango b = M x (rango b + 1) a b | otherwise = M x (rango a + 1) b a -- | (mezcla m1 m2) es el montículo obtenido mezclando los montículos m1 y -- m2. Por ejemplo, -- -- > ghci> mezcla (foldr inserta vacio [6,1,4,8]) (foldr inserta vacio [7,5]) -- > M 1 2 -- > (M 5 2 -- > (M 7 1 Vacio Vacio) -- > (M 6 1 Vacio Vacio)) -- > (M 4 1 -- > (M 8 1 Vacio Vacio) -- > Vacio) mezcla :: Ord a => Monticulo a -> Monticulo a -> Monticulo a mezcla m Vacio = m mezcla Vacio m = m mezcla m1@(M x _ a1 b1) m2@(M y _ a2 b2) | x <= y = creaM x a1 (mezcla b1 m2) | otherwise = creaM y a2 (mezcla m1 b2) -- | (inserta x m) es el montículo obtenido añadiendo el elemento x al -- montículo m. Por ejemplo, -- -- > ghci> inserta 3 (foldr inserta vacio [6,1,4,8]) -- > M 1 2 -- > (M 4 1 (M 8 1 Vacio Vacio) Vacio) -- > (M 3 1 (M 6 1 Vacio Vacio) Vacio) inserta :: Ord a => a -> Monticulo a -> Monticulo a inserta x m = mezcla (M x 1 Vacio Vacio) m -- | (menor m) es el menor elemento del montículo m. Por ejemplo, -- -- > menor (foldr inserta vacio [6,1,4,8]) == 1 -- > menor (foldr inserta vacio [7,5]) == 5 menor :: Ord a => Monticulo a -> a menor (M x _ _ _) = x menor Vacio = error "menor: monticulo vacio" -- | (resto m) es el montículo obtenido eliminando el menor elemento del -- montículo m. Por ejemplo, -- -- > ghci> resto (foldr inserta vacio [6,1,4,8]) -- > M 4 2 (M 8 1 Vacio Vacio) (M 6 1 Vacio Vacio) resto :: Ord a => Monticulo a -> Monticulo a resto Vacio = error "resto: monticulo vacio" resto (M x _ a b) = mezcla a b -- | (esVacio m) se verifica si m es el montículo vacío. esVacio :: Ord a => Monticulo a -> Bool esVacio Vacio = True esVacio _ = False -- | (valido m) se verifica si m es un montículo; es decir, es un árbol -- binario en el que los valores de cada nodo es menor o igual que los -- valores de sus hijos. Por ejemplo, -- -- > valido (foldr inserta vacio [6,1,4,8]) == True -- > valido (foldr inserta vacio [7,5]) == True -- > valido (M 3 5 (M 2 1 Vacio Vacio) Vacio) == False valido :: Ord a => Monticulo a -> Bool valido Vacio = True valido (M x _ Vacio Vacio) = True valido (M x _ m1@(M x1 n1 a1 b1) Vacio) = x <= x1 && valido m1 valido (M x _ Vacio m2@(M x2 n2 a2 b2)) = x <= x2 && valido m2 valido (M x _ m1@(M x1 n1 a1 b1) m2@(M x2 n2 a2 b2)) = x <= x1 && valido m1 && x <= x2 && valido m2 -- | (elementos m) es la lista de los elementos del montículo m. Por -- ejemplo, -- -- > elementos (foldr inserta vacio [6,1,4,8]) == [1,4,8,6] elementos :: Ord a => Monticulo a -> [a] elementos Vacio = [] elementos (M x _ a b) = x : elementos a ++ elementos b -- | (equivMonticulos m1 m2) se verifica si los montículos m1 y m2 tienen -- los mismos elementos. Por ejemplo, -- -- > ghci> equivMonticulos (foldr inserta vacio [6,1,4]) (foldr inserta vacio [6,4,1]) -- > True equivMonticulos :: Ord a => Monticulo a -> Monticulo a -> Bool equivMonticulos m1 m2 = sort (elementos m1) == sort (elementos m2) -- Los montículos son comparables por igualdad. instance Ord a => Eq (Monticulo a) where (==) = equivMonticulos -- --------------------------------------------------------------------- -- Funciones auxiliares -- -- --------------------------------------------------------------------- -- | (menorTodos x m) comprueba si x es menor que todos los elementos de m menorTodos:: Ord a => a -> Monticulo a -> Bool menorTodos x Vacio = True menorTodos x (M y n a b) = x <= y && valido (M y n a b) -- | (enMonticulo x m) se verifica si x es un elemento del montículo -- m. Por ejemplo, -- -- > enMonticulo 4 (foldr inserta vacio [6,1,4,8]) == True -- > enMonticulo 5 (foldr inserta vacio [6,1,4,8]) == False enMonticulo x Vacio = False enMonticulo x (M y _ a b) | x < y = False | x == y = True | otherwise = enMonticulo x a || enMonticulo x b