Ir al contenido principal

Listas disjuntas


Definir la función

disjuntas :: Ord a => [a] -> [a] -> Bool

tal que (disjuntas xs ys) se verifica si las listas ordenadas crecientemente xs e ys son disjuntas. Por ejemplo,

disjuntas [2,5]   [1,4,7]                  ==  True
disjuntas [2,5,7] [1,4,7]                  ==  False
disjuntas [1..1000000] [3000000..4000000]  ==  True

Soluciones

import Data.Set (disjoint, fromDistinctAscList)
import Data.List.Ordered (isect)
import Test.Hspec (Spec, describe, hspec, it, shouldBe)
import Test.QuickCheck

-- 1ª solución
-- ===========

disjuntas1 :: Ord a => [a] -> [a] -> Bool
disjuntas1 [] _ = True
disjuntas1 _ [] = True
disjuntas1 (x:xs) (y:ys)
  | x < y     = disjuntas1 xs (y:ys)
  | x > y     = disjuntas1 (x:xs) ys
  | otherwise = False

-- 2ª solución
-- ===========

disjuntas2 :: Ord a => [a] -> [a] -> Bool
disjuntas2 xs'@(x:xs) ys'@(y:ys)
  | x < y     = disjuntas2 xs ys'
  | x > y     = disjuntas2 xs' ys
  | otherwise = False
disjuntas2 _ _ = True

-- 3ª solución
-- ===========

disjuntas3 :: Ord a => [a] -> [a] -> Bool
disjuntas3 [] _ = True
disjuntas3 _ [] = True
disjuntas3 (x:xs) (y:ys) =
  case compare x y of
    LT -> disjuntas3 xs (y:ys)
    GT -> disjuntas3 (x:xs) ys
    EQ -> False

-- 4ª solución
-- ===========

disjuntas4 :: Ord a => [a] -> [a] -> Bool
disjuntas4 xs ys =
  disjoint (fromDistinctAscList xs) (fromDistinctAscList ys)

-- 5ª solución
-- ===========

disjuntas5 :: Ord a => [a] -> [a] -> Bool
disjuntas5 xs ys = null (isect xs ys)

-- Verificación
-- ============

verifica :: IO ()
verifica = hspec spec

specG :: ([Int] -> [Int] -> Bool) -> Spec
specG disjuntas = do
  it "e1" $
    disjuntas [2,5]   [1,4,7]                  `shouldBe`  True
  it "e2" $
    disjuntas [2,5,7] [1,4,7]                  `shouldBe`  False

spec :: Spec
spec = do
  describe "def. 1" $ specG disjuntas1
  describe "def. 2" $ specG disjuntas2
  describe "def. 3" $ specG disjuntas3
  describe "def. 4" $ specG disjuntas4
  describe "def. 5" $ specG disjuntas5

-- La verificación es
--    λ> verifica
--    10 examples, 0 failures

-- Comprobación de equivalencia
-- ============================

-- La propiedad es
prop_equivalencia :: OrderedList Int -> OrderedList Int -> Bool
prop_equivalencia (Ordered xs) (Ordered ys) =
  all (== disjuntas1 xs ys)
      [disjuntas2 xs ys,
       disjuntas3 xs ys,
       disjuntas4 xs ys,
       disjuntas5 xs ys]

-- La comprobación es
--    λ> quickCheck prop_equivalencia
--    +++ OK, passed 100 tests.

-- Comparación de eficiencia
-- =========================

-- La comparación es
--    λ> :set +s
--    λ> disjuntas1 [1..10^7] [3*10^7..4*10^7]
--    True
--    (3.57 secs, 2,640,601,080 bytes)
--    λ> disjuntas2 [1..10^7] [3*10^7..4*10^7]
--    True
--    (3.18 secs, 1,920,601,080 bytes)
--    λ> disjuntas3 [1..10^7] [3*10^7..4*10^7]
--    True
--    (4.17 secs, 3,360,601,080 bytes)
--    λ> disjuntas4 [1..10^7] [3*10^7..4*10^7]
--    True
--    (4.16 secs, 2,240,620,912 bytes)
--    λ> disjuntas5 [1..10^7] [3*10^7..4*10^7]
--    True
--    (0.29 secs, 720,601,152 bytes)