-- |
-- Module      : RecorridoEnProfundidad
-- Description : Recorrido de grafos en profundidad.
-- License     : Creative Commons
-- Maintainer  : José A. Alonso
-- 
-- = Recorrido de grafos en profundidad
-- 
-- En los ejemplos se usará el siguiente grafo
-- 
-- >   +---> 2 <---+
-- >   |           |
-- >   |           |
-- >   1 --> 3 --> 6 --> 5
-- >   |                 |
-- >   |                 |
-- >   +---> 4 <---------+
-- definido por
-- > g = creaGrafo D (1,6) 
-- >               [(1,2,0),(1,3,0),(1,4,0),(3,6,0),(5,4,0),(6,2,0),(6,5,0)]

module I1M.RecorridoEnProfundidad (recorridoEnProfundidad, 
                                   recorridoEnProfundidad') where

-- ---------------------------------------------------------------------
-- Librerías auxiliares                                               --
-- ---------------------------------------------------------------------

import Data.Ix
import I1M.Grafo

-- ---------------------------------------------------------------------
-- Ejemplo de grafo                                                   --
-- ---------------------------------------------------------------------

-- g es el grafo
--    +---> 2 <---+
--    |           |
--    |           |
--    1 --> 3 --> 6 --> 5
--    |                 |
--    |                 |
--    +---> 4 <---------+

-- g = creaGrafo D (1,6) 
--               [(1,2,0),(1,3,0),(1,4,0),(3,6,0),(5,4,0),(6,2,0),(6,5,0)]

-- ---------------------------------------------------------------------
-- Recorrido en profundidad                                            --
-- ---------------------------------------------------------------------

-- | (recorridoEnProfundidad i g) es el recorrido en profundidad del grafo g
-- desde el vértice i. Por ejemplo,
-- 
-- > recorridoEnProfundidad 1 g  ==  [1,2,3,6,5,4]
recorridoEnProfundidad :: (Num p, Ix v) => v -> Grafo v p -> [v]
recorridoEnProfundidad :: forall p v. (Num p, Ix v) => v -> Grafo v p -> [v]
recorridoEnProfundidad v
i Grafo v p
g = [v] -> [v] -> [v]
rp [v
i] [] where 
  rp :: [v] -> [v] -> [v]
rp [] [v]
vis    = [v]
vis
  rp (v
c:[v]
cs) [v]
vis 
    | v
c v -> [v] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [v]
vis = [v] -> [v] -> [v]
rp [v]
cs [v]
vis
    | Bool
otherwise    = [v] -> [v] -> [v]
rp (Grafo v p -> v -> [v]
forall v p. (Ix v, Num p) => Grafo v p -> v -> [v]
adyacentes Grafo v p
g v
c [v] -> [v] -> [v]
forall a. [a] -> [a] -> [a]
++ [v]
cs) ([v]
vis [v] -> [v] -> [v]
forall a. [a] -> [a] -> [a]
++ [v
c])

-- Traza del cálculo de (recorridoEnProfundidad 1 g)
--    recorridoEnProfundidad 1 g
--    = rp [1]     []
--    = rp [2,3,4] [1]
--    = rp [3,4]   [1,2]
--    = rp [6,4]   [1,2,3]
--    = rp [2,5,4] [1,2,3,6]
--    = rp [5,4]   [1,2,3,6]
--    = rp [4,4]   [1,2,3,6,5]
--    = rp [4]     [1,2,3,6,5,4]
--    = rp []      [1,2,3,6,5,4]
--    = [1,2,3,6,5,4]

-- ---------------------------------------------------------------------
-- Recorrido en profundidad con acumuladores                           --
-- ---------------------------------------------------------------------

-- | (recorridoEnProfundidad' i g) es el recorrido en profundidad del
-- grafo g desde el vértice i, usando la lista de los visitados como
-- acumulador. Por ejemplo, 
-- 
-- > recorridoEnProfundidad' 1 g  ==  [1,2,3,6,5,4]
recorridoEnProfundidad' :: (Num p, Ix v) => v -> Grafo v p -> [v]
recorridoEnProfundidad' :: forall p v. (Num p, Ix v) => v -> Grafo v p -> [v]
recorridoEnProfundidad' v
i Grafo v p
g = [v] -> [v]
forall a. [a] -> [a]
reverse ([v] -> [v] -> [v]
rp [v
i] []) where
  rp :: [v] -> [v] -> [v]
rp [] [v]
vis     = [v]
vis
  rp (v
c:[v]
cs) [v]
vis 
    | v
c v -> [v] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [v]
vis = [v] -> [v] -> [v]
rp [v]
cs [v]
vis
    | Bool
otherwise    = [v] -> [v] -> [v]
rp ( Grafo v p -> v -> [v]
forall v p. (Ix v, Num p) => Grafo v p -> v -> [v]
adyacentes Grafo v p
g v
c [v] -> [v] -> [v]
forall a. [a] -> [a] -> [a]
++ [v]
cs) (v
c v -> [v] -> [v]
forall a. a -> [a] -> [a]
: [v]
vis)

-- Traza del cálculo de (recorridoEnProfundidad' 1 g)
--    RecorridoEnProfundidad' 1 g
--    = reverse (rp [1]     [])
--    = reverse (rp [2,3,4] [1])
--    = reverse (rp [3,4]   [2,1])
--    = reverse (rp [6,4]   [3,2,1])
--    = reverse (rp [2,5,4] [6,3,2,1])
--    = reverse (rp [5,4]   [6,3,2,1])
--    = reverse (rp [4,4]   [5,6,3,2,1])
--    = reverse (rp [4]     [4,5,6,3,2,1])
--    = reverse (rp []      [4,5,6,3,2,1])
--    = reverse [4,5,6,3,2,1]
--    = [1,2,3,6,5,4]