Emparejamiento de árboles
Los árboles se pueden representar mediante el siguiente tipo de datos
data Arbol a = N a [Arbol a] deriving (Show, Eq)
Por ejemplo, los árboles
1 3 / \ /|\ 6 3 / | \ | 5 4 7 5 | /\ 6 2 1
se representan por
ej1, ej2 :: Arbol Int ej1 = N 1 [N 6 [],N 3 [N 5 []]] ej2 = N 3 [N 5 [N 6 []], N 4 [], N 7 [N 2 [], N 1 []]]
Definir la función
emparejaArboles :: (a -> b -> c) -> Arbol a -> Arbol b -> Arbol c
tal que (emparejaArboles f a1 a2)
es el árbol obtenido aplicando la función f
a los elementos de los árboles a1
y a2
que se encuentran en la misma posición. Por ejemplo,
λ> emparejaArboles (+) (N 1 [N 2 [], N 3[]]) (N 1 [N 6 []]) N 2 [N 8 []] λ> emparejaArboles (+) ej1 ej2 N 4 [N 11 [],N 7 []] λ> emparejaArboles (+) ej1 ej1 N 2 [N 12 [],N 6 [N 10 []]]
Soluciones
import Data.Tree (Tree (..)) import Control.Monad.Zip (mzipWith) import Test.Hspec (Spec, describe, hspec, it, shouldBe) import Test.QuickCheck (Arbitrary, Gen, arbitrary, generate, sublistOf, sized, quickCheck) data Arbol a = N a [Arbol a] deriving (Show, Eq) ej1, ej2 :: Arbol Int ej1 = N 1 [N 6 [],N 3 [N 5 []]] ej2 = N 3 [N 5 [N 6 []], N 4 [], N 7 [N 2 [], N 1 []]] -- 1ª solución -- =========== emparejaArboles1 :: (a -> b -> c) -> Arbol a -> Arbol b -> Arbol c emparejaArboles1 f (N x xs) (N y ys) = N (f x y) (emparejaListaArboles f xs ys) emparejaListaArboles :: (a -> b -> c) -> [Arbol a] -> [Arbol b] -> [Arbol c] emparejaListaArboles _ [] _ = [] emparejaListaArboles _ _ [] = [] emparejaListaArboles f (x:xs) (y:ys) = emparejaArboles1 f x y : emparejaListaArboles f xs ys -- 2ª solución -- =========== emparejaArboles2 :: (a -> b -> c) -> Arbol a -> Arbol b -> Arbol c emparejaArboles2 f (N x xs) (N y ys) = N (f x y) (zipWith (emparejaArboles2 f) xs ys) -- 3ª solución -- =========== emparejaArboles3 :: (a -> b -> c) -> Arbol a -> Arbol b -> Arbol c emparejaArboles3 f x y = treeAarbol (mzipWith f (arbolAtree x) (arbolAtree y)) arbolAtree :: Arbol a -> Tree a arbolAtree (N x xs) = Node x (map arbolAtree xs) treeAarbol :: Tree a -> Arbol a treeAarbol (Node x xs) = N x (map treeAarbol xs) -- Verificación -- ============ verifica :: IO () verifica = hspec spec specG :: ((Int -> Int -> Int) -> Arbol Int -> Arbol Int -> Arbol Int) -> Spec specG emparejaArboles = do it "e1" $ show (emparejaArboles (+) (N 1 [N 2 [], N 3[]]) (N 1 [N 6 []])) `shouldBe` "N 2 [N 8 []]" it "e2" $ show (emparejaArboles (+) ej1 ej2) `shouldBe` "N 4 [N 11 [],N 7 []]" it "e3" $ show (emparejaArboles (+) ej1 ej1) `shouldBe` "N 2 [N 12 [],N 6 [N 10 []]]" spec :: Spec spec = do describe "def. 1" $ specG emparejaArboles1 describe "def. 2" $ specG emparejaArboles2 describe "def. 3" $ specG emparejaArboles3 -- La verificación es -- λ> verifica -- 9 examples, 0 failures -- Comprobación de equivalencia -- ============================ -- (arbolArbitrario n) es un árbol aleatorio de orden n. Por ejemplo, -- λ> generate (arbolArbitrario 5 :: Gen (Arbol Int)) -- N (-26) [N 8 [N 6 [N 11 []]],N 7 []] -- λ> generate (arbolArbitrario 5 :: Gen (Arbol Int)) -- N 1 [] -- λ> generate (arbolArbitrario 5 :: Gen (Arbol Int)) -- N (-19) [N (-11) [],N 25 [],N 19 [N (-27) [],N (-19) [N 17 []]]] arbolArbitrario :: Arbitrary a => Int -> Gen (Arbol a) arbolArbitrario n = do x <- arbitrary ms <- sublistOf [0 .. n `div` 2] as <- mapM arbolArbitrario ms return (N x as) -- Arbol es una subclase de Arbitraria instance Arbitrary a => Arbitrary (Arbol a) where arbitrary = sized arbolArbitrario -- La propiedad es prop_emparejaArboles :: Arbol Int -> Arbol Int -> Bool prop_emparejaArboles x y = emparejaArboles1 (+) x y == emparejaArboles2 (+) x y && emparejaArboles1 (*) x y == emparejaArboles2 (*) x y && emparejaArboles1 (+) x y == emparejaArboles3 (+) x y && emparejaArboles1 (*) x y == emparejaArboles3 (*) x y -- La comprobación es -- λ> quickCheck prop_emparejaArboles -- +++ OK, passed 100 tests. -- Comparación de eficiencia -- ========================= -- La comparación es -- λ> a500 <- generate (arbolArbitrario 500 :: Gen (Arbol Int)) -- λ> emparejaArboles1 (+) a500 a500 == emparejaArboles1 (+) a500 a500 -- True -- (3.03 secs, 1,981,353,912 bytes) -- λ> emparejaArboles2 (+) a500 a500 == emparejaArboles1 (+) a500 a500 -- True -- (2.12 secs, 1,325,826,688 bytes) -- λ> emparejaArboles3 (+) a500 a500 == emparejaArboles1 (+) a500 a500 -- True -- (2.57 secs, 1,937,547,296 bytes)