Ir al contenido principal

TAD de los polinomios - Valor de un polinomio en un punto

Utilizando el tipo abstracto de datos de los polinomios definir las funciones

   valor :: (Num a, Eq a) => Polinomio a -> a -> a

tal que valor p c es el valor del polinomio p al sustituir su variable por c. Por ejemplo,

   λ> ejPol = consPol 4 3 (consPol 2 (-5) (consPol 0 3 polCero))
   λ> ejPol
   3*x^4 + -5*x^2 + 3
   λ> valor ejPol 0
   3
   λ> valor ejPol 1
   1
   λ> valor ejPol (-2)
   31

Leer más…

TAD de los polinomios - Producto de polinomios

Utilizando el tipo abstracto de datos de los polinomios definir las funciones

   multPol :: (Num a, Eq a) => Polinomio a -> Polinomio a -> Polinomio a

tal que multPol p q es el producto de los polinomios p y q. Por ejemplo,

   λ> ejPol1 = consPol 4 3 (consPol 2 (-5) (consPol 0 3 polCero))
   λ> ejPol2 = consPol 5 1 (consPol 2 5 (consPol 1 4 polCero))
   λ> ejPol1
   3*x^4 + -5*x^2 + 3
   λ> ejPol2
   x^5 + 5*x^2 + 4*x
   λ> multPol ejPol1 ejPol2
   3*x^9 + -5*x^7 + 15*x^6 + 15*x^5 + -25*x^4 + -20*x^3 + 15*x^2 + 12*x

Comprobar con QuickCheck las siguientes propiedades

  • El producto de polinomios es conmutativo.
  • El producto es distributivo respecto de la suma.

Leer más…

TAD de los polinomios - Suma de polinomios

Utilizando el tipo abstracto de datos de los polinomios definir las funciones

   sumaPol :: (Num a, Eq a) => Polinomio a -> Polinomio a -> Polinomio a

tal que (sumaPol p q) es la suma de los polinomios p y q. Por ejemplo,

   λ> ejPol1 = consPol 4 3 (consPol 2 (-5) (consPol 0 3 polCero))
   λ> ejPol2 = consPol 5 1 (consPol 2 5 (consPol 1 4 polCero))
   λ> ejPol1
   3*x^4 + -5*x^2 + 3
   λ> ejPol2
   x^5 + 5*x^2 + 4*x
   λ> sumaPol ejPol1 ejPol2
   x^5 + 3*x^4 + 4*x + 3

Comprobar con QuickCheck las siguientes propiedades:

  • polCero es el elemento neutro de la suma.
  • la suma es conmutativa.

Leer más…

TAD de los polinomios - Transformaciones entre polinomios y listas densas

Utilizando el tipo abstracto de datos de los polinomios definir las funciones

   densaApolinomio :: (Num a, Eq a) => [a] -> Polinomio a
   polinomioAdensa :: (Num a, Eq a) => Polinomio a -> [a]

tales que

  • densaApolinomio xs es el polinomio cuya representación densa es xs. Por ejemplo,
     λ> densaApolinomio [9,0,0,5,0,4,7]
     9*x^6 + 5*x^3 + 4*x + 7
  • polinomioAdensa p es la representación densa del polinomio p. Por ejemplo,
     λ> ejPol = consPol 6 9 (consPol 3 5 (consPol 1 4 (consPol 0 7 polCero)))
     λ> ejPol
     9*x^6 + 5*x^3 + 4*x + 7
     λ> polinomioAdensa ejPol
     [9,0,0,5,0,4,7]

Comprobar con QuickCheck que ambas funciones son inversas.

Leer más…

TAD de los polinomios - Coeficiente del término de grado k

Utilizando el tipo abstracto de datos de los polinomios definir las funciones

   coeficiente :: (Num a, Eq a) => Int -> Polinomio a -> a

tal que coeficiente k p es el coeficiente del término de grado k del polinomio p. Por ejemplo,

   λ> ejPol = consPol 5 1 (consPol 2 5 (consPol 1 4 polCero))
   λ> ejPol
   x^5 + 5*x^2 + 4*x
   λ> coeficiente 2 ejPol
   5
   λ> coeficiente 3 ejPol
   0

Leer más…

TAD de los polinomios - Transformaciones entre polinomios y listas dispersas

Utilizando el tipo abstracto de datos de los polinomios definir las funciones

   dispersaApolinomio :: (Num a, Eq a) => [(Int,a)] -> Polinomio a
   polinomioAdispersa :: (Num a, Eq a) => Polinomio a -> [(Int,a)]

tales que

  • dispersaApolinomio ps es el polinomiocuya representación dispersa es ps. Por ejemplo,
     λ> dispersaApolinomio [(6,9),(3,5),(1,4),(0,7)]
     9*x^6 + 5*x^3 + 4*x + 7
  • polinomioAdispersa p es la representación dispersa del polinomio p. Por ejemplo,
     λ> ejPol = consPol 6 9 (consPol 3 5 (consPol 1 4 (consPol 0 7 polCero)))
     λ> ejPol
     9*x^6 + 5*x^3 + 4*x + 7
     λ> polinomioAdispersa ejPol
     [(6,9),(3,5),(1,4),(0,7)]

Comprobar con QuickCheck que ambas funciones son inversas.

Leer más…

TAD de los polinomios - Transformaciones entre las representaciones dispersa y densa

Definir las funciones

   densaAdispersa :: (Num a, Eq a) => [a] -> [(Int,a)]
   dispersaAdensa :: (Num a, Eq a) => [(Int,a)] -> [a]

tales que

  • densaAdispersa xs es la representación dispersa del polinomio cuya representación densa es xs. Por ejemplo,
     λ> densaAdispersa [9,0,0,5,0,4,7]
     [(6,9),(3,5),(1,4),(0,7)]
  • dispersaAdensa ps es la representación densa del polinomio cuya representación dispersa es ps. Por ejemplo,
     λ> dispersaAdensa [(6,9),(3,5),(1,4),(0,7)]
     [9,0,0,5,0,4,7]

Comprobar con QuickCheck que las funciones densaAdispersa y dispersaAdensa son inversas.

Leer más…

El tipo abstracto de datos de los polinomios

1. El tipo abstracto de datos de los polinomios

Un polinomio es una expresión matemática compuesta por una suma de términos, donde cada término es el producto de un coeficiente y una variable elevada a una potencia. Por ejemplo, el polinomio 3x^2+2x-1 tiene un término de segundo grado (3x^2), un término de primer grado (2x) y un término constante (-1).

Las operaciones que definen al tipo abstracto de datos (TAD) de los polinomios (cuyos coeficientes son del tipo a) son las siguientes:

   polCero   :: Polinomio a
   esPolCero :: Polinomio a -> Bool
   consPol   :: (Num a, Eq a) => Int -> a -> Polinomio a -> Polinomio a
   grado     :: Polinomio a -> Int
   coefLider :: Num a => Polinomio a -> a
   restoPol  :: (Num a, Eq a) => Polinomio a -> Polinomio a

tales que

  • polCero es el polinomio cero.
  • (esPolCero p) se verifica si p es el polinomio cero.
  • (consPol n b p) es el polinomio bx^n+p
  • (grado p) es el grado del polinomio p.
  • (coefLider p) es el coeficiente líder del polinomio p.
  • (restoPol p) es el resto del polinomio p.

Por ejemplo, el polinomio

   3*x^4 + -5*x^2 + 3

se representa por

   consPol 4 3 (consPol 2 (-5) (consPol 0 3 polCero))

Las operaciones tienen que verificar las siguientes propiedades:

  • esPolCero polCero
  • n > grado p && b /= 0 ==> not (esPolCero (consPol n b p))
  • consPol (grado p) (coefLider p) (restoPol p) == p
  • n > grado p && b /= 0 ==> grado (consPol n b p) == n
  • n > grado p && b /= 0 ==> coefLider (consPol n b p) == b
  • n > grado p && b /= 0 ==> restoPol (consPol n b p) == p

Leer más…

Clausura transitiva

Usando el tipo de las relaciones binarias, definir las funciones

   clausuraTransitiva :: Eq a => Rel a -> Rel a

tal que clausuraTransitiva r es la clausura transitiva de r; es decir, la menor relación transitiva que contiene a r. Por ejemplo,

   λ> clausuraTransitiva (R ([1..6],[(1,2),(2,5),(5,6)]))
   R ([1,2,3,4,5,6],[(1,2),(2,5),(5,6),(1,5),(2,6),(1,6)])

Comprobar con QuickCheck que clausuraTransitiva es transitiva.

Leer más…

Clausura simétrica

Usando el tipo de las relaciones binarias, definir las funciones

   clausuraSimetrica :: Eq a => Rel a -> Rel a

tal que clausuraSimetrica r es la clausura simétrica de r; es decir, la menor relación simétrica que contiene a r. Por ejemplo,

   λ> clausuraSimetrica (R ([1,3,5],[(1,1),(3,1),(1,5)]))
   R ([1,3,5],[(1,1),(3,1),(1,5),(1,3),(5,1)])

Comprobar con QuickCheck que clausuraSimetrica es simétrica.

Leer más…

Relaciones totales

Usando el tipo de las relaciones binarias, definir las funciones

   total :: Eq a => Rel a -> Bool

tal que total r se verifica si la relación r es total; es decir, si para cualquier par x, y de elementos del universo de r, se tiene que x está relacionado con y o y está relacionado con x. Por ejemplo,

   total (R ([1,3],[(1,1),(3,1),(3,3)]))  ==  True
   total (R ([1,3],[(1,1),(3,1)]))        ==  False
   total (R ([1,3],[(1,1),(3,3)]))        ==  False

Leer más…

Relaciones antisimétricas

Usando el tipo de las relaciones binarias, definir las funciones

   antisimetrica :: Eq a => Rel a -> Bool

tal que antisimetrica r se verifica si la relación r es antisimétrica; es decir, si (x,y) e (y,x) están relacionado, entonces x=y. Por ejemplo,

   antisimetrica (R ([1,2],[(1,2)]))        ==  True
   antisimetrica (R ([1,2],[(1,2),(2,1)]))  ==  False
   antisimetrica (R ([1,2],[(1,1),(2,1)]))  ==  True

Leer más…

Relaciones de equivalencia

Usando el tipo de las relaciones binarias, definir las funciones

   esEquivalencia :: Ord a => Rel a -> Bool

tal que esEquivalencia r se verifica si la relación r es de equivalencia. Por ejemplo,

   λ> esEquivalencia (R ([1,3,5],[(1,1),(1,3),(3,1),(3,3),(5,5)]))
   True
   λ> esEquivalencia (R ([1,2,3,5],[(1,1),(1,3),(3,1),(3,3),(5,5)]))
   False
   λ> esEquivalencia (R ([1,3,5],[(1,1),(1,3),(3,3),(5,5)]))
   False

Leer más…

Relaciones binarias

Una relación binaria R sobre un conjunto A se puede mediante un par (u,g) donde u es la lista de los elementos de tipo A (el universo de R) y g es la lista de pares de elementos de u (el grafo de R).

Definir el tipo de dato (Rel a), para representar las relaciones binarias sobre a, y la función

   esRelacionBinaria :: Eq a => Rel a -> Bool

tal que esRelacionBinaria r se verifica si r es una relación binaria. Por ejemplo,

   λ> esRelacionBinaria (R ([1, 3], [(3, 1), (3, 3)]))
   True
   λ> esRelacionBinaria (R ([1, 3], [(3, 1), (3, 2)]))
   False

Además, definir un generador de relaciones binarias y comprobar que las relaciones que genera son relaciones binarias.

Leer más…

TAD de los conjuntos - TAD Producto cartesiano

Utilizando el tipo abstracto de datos de los conjuntos definir la función

   productoC :: (Ord a, Ord b) => Conj a -> Conj b -> Conj (a,b)

tal que productoC c1 c2 es el producto cartesiano de los conjuntos c1 y c2. Por ejemplo,

   λ> ej1 = inserta 2 (inserta 5 vacio)
   λ> ej2 = inserta 9 (inserta 4 (inserta 3 vacio))
   λ> productoC ej1 ej2
   {(2,3), (2,4), (2,9), (5,3), (5,4), (5,9)}

Leer más…

TAD de los conjuntos - Partición de un conjunto según una propiedad

Utilizando el tipo abstracto de datos de los conjuntos definir la función

   particion :: Ord a => (a -> Bool) -> Conj a -> (Conj a, Conj a)

tal que particion c es el par formado por dos conjuntos: el de los elementos de c que verifican p y el de los elementos que no lo verifican. Por ejemplo,

   λ> ej = inserta 5 (inserta 4 (inserta 7 (inserta 2 vacio)))
   λ> particion even ej
   ({2, 4},{5, 7})

Leer más…

TAD de los conjuntos - Subconjunto determinado por una propiedad

Utilizando el tipo abstracto de datos de los conjuntos definir la función

   filtra :: Ord a => (a -> Bool) -> Conj a -> Conj a

tal filtra p c es el conjunto de elementos de c que verifican el predicado p. Por ejemplo,

   λ> filtra even (inserta 5 (inserta 4 (inserta 7 (inserta 2 vacio))))
   {2, 4}
   λ> filtra odd (inserta 5 (inserta 4 (inserta 7 (inserta 2 vacio))))
   {5, 7}

Leer más…

TAD de los conjuntos - Diferencia simétrica

Utilizando el tipo abstracto de datos de los conjuntos definir la función

   diferenciaSimetrica :: Ord a => Conj a -> Conj a -> Conj a

tal que diferenciaSimetrica c1 c2 es la diferencia simétrica de los conjuntos c1 y c2. Por ejemplo,

   λ> ej1 = inserta 5 (inserta 3 (inserta 2 (inserta 7 vacio)))
   λ> ej2 = inserta 7 (inserta 4 (inserta 3 vacio))
   λ> diferenciaSimetrica ej1 ej2
   {2, 4, 5}

Leer más…

TAD de los conjuntos - Diferencia de conjuntos

Utilizando el tipo abstracto de datos de los conjuntos definir la función

   diferencia :: Ord a => Conj a -> Conj a -> Conj a

tal que diferencia c1 c2 es el conjunto de los elementos de c1 que no son elementos de c2. Por ejemplo,

   λ> ej1 = inserta 5 (inserta 3 (inserta 2 (inserta 7 vacio)))
   λ> ej2 = inserta 7 (inserta 4 (inserta 3 vacio))
   λ> diferencia ej1 ej2
   {2, 5}
   λ> diferencia ej2 ej1
   {4}
   λ> diferencia ej1 ej1
   {}

Leer más…

TAD de los conjuntos - Conjuntos disjuntos

Utilizando el tipo abstracto de datos de los conjuntos definir la función

   disjuntos :: Ord a => Conj a -> Conj a -> Bool

tal que disjuntos c1 c2 se verifica si los conjuntos c1 y c2 son disjuntos. Por ejemplo,

   λ> ej1 = inserta 2 (inserta 5 vacio)
   λ> ej2 = inserta 4 (inserta 3 vacio)
   λ> ej3 = inserta 5 (inserta 3 vacio)
   λ> disjuntos ej1 ej2
   True
   λ> disjuntos ej1 ej3
   False

Leer más…

TAD de los conjuntos - Intersección de varios conjuntos

Utilizando el tipo abstracto de datos de los conjuntos definir la función

   interseccionG :: Ord a => [Conj a] -> Conj a

tal que interseccionG cs es la intersección de la lista de conjuntos cs. Por ejemplo,

   λ> ej1 = inserta 2 (inserta 3 (inserta 5 vacio))
   λ> ej2 = inserta 5 (inserta 2 (inserta 7 vacio))
   λ> ej3 = inserta 3 (inserta 2 (inserta 5 vacio))
   λ> interseccionG [ej1, ej2, ej3]
   {2, 5}

Leer más…

TAD de los conjuntos - Reconocimiento de subconjunto propio

Utilizando el tipo abstracto de datos de los conjuntos definir la función

   subconjuntoPropio :: Ord a => Conj a -> Conj a -> Bool

tal subconjuntoPropio c1 c2 se verifica si c1 es un subconjunto propio de c2. Por ejemplo,

   λ> ej1 = inserta 5 (inserta 2 vacio)
   λ> ej2 = inserta 3 (inserta 2 (inserta 5 vacio))
   λ> ej3 = inserta 3 (inserta 4 (inserta 5 vacio))
   λ> ej4 = inserta 2 (inserta 5 vacio)
   λ> subconjuntoPropio ej1 ej2
   True
   λ> subconjuntoPropio ej1 ej3
   False
   λ> subconjuntoPropio ej1 ej4
   False

Leer más…

TAD de los conjuntos - Reconocimiento de subconjunto

Utilizando el tipo abstracto de datos de los conjuntos definir la función

   subconjunto :: Ord a => Conj a -> Conj a -> Bool

tal que subconjunto c1 c2 se verifica si todos los elementos de c1 pertenecen a c2. Por ejemplo,

   λ> ej1 = inserta 5 (inserta 2 vacio)
   λ> ej2 = inserta 3 (inserta 2 (inserta 5 vacio))
   λ> ej3 = inserta 3 (inserta 4 (inserta 5 vacio))
   λ> subconjunto ej1 ej2
   True
   λ> subconjunto ej1 ej3
   False

Leer más…

TAD de los conjuntos - Transformaciones entre conjuntos y listas

Utilizando el tipo abstracto de datos de los conjuntos definir las funciones

   listaAconjunto :: [a] -> Conj a
   conjuntoAlista :: Conj a -> [a]

tales que

  • listaAconjunto xs es el conjunto formado por los elementos de xs. Por ejemplo,
     λ> listaAconjunto [3, 2, 5]
     {2, 3, 5}
  • conjuntoAlista c es la lista formada por los elementos del conjunto c. Por ejemplo,
     λ> conjuntoAlista (inserta 5 (inserta 2 (inserta 3 vacio)))
     [2,3,5]

Comprobar con QuickCheck que ambas funciones son inversa; es decir,

   conjuntoAlista (listaAconjunto xs) = sort (nub xs)
   listaAconjunto (conjuntoAlista c)  = c

Leer más…

El tipo abstracto de datos de los conjuntos

1. El tipo abstracto de datos de los conjuntos

Un conjunto es una estructura de datos, caracterizada por ser una colección de elementos en la que no importe ni el orden ni la repetición de elementos.

Las operaciones que definen al tipo abstracto de datos (TAD) de los conjuntos (cuyos elementos son del tipo a) son las siguientes:

   vacio      :: Conj a
   inserta    :: Ord a => a -> Conj a -> Conj a
   menor      :: Ord a => Conj a -> a
   elimina    :: Ord a => a -> Conj a -> Conj a
   pertenece  :: Ord a => a -> Conj a -> Bool
   esVacio    :: Conj a -> Bool

tales que

  • vacio es el conjunto vacío.
  • (inserta x c) es el conjunto obtenido añadiendo el elemento x al conjunto c.
  • (menor c) es el menor elemento del conjunto c.
  • (elimina x c) es el conjunto obtenido eliminando el elemento x del conjunto c.
  • (pertenece x c) se verifica si x pertenece al conjunto c.
  • (esVacio c) se verifica si c es el conjunto vacío.

Las operaciones tienen que verificar las siguientes propiedades:

  • inserta x (inserta x c) == inserta x c
  • inserta x (inserta y c) == inserta y (inserta x c)
  • not (pertenece x vacio)
  • pertenece y (inserta x c) == (x==y) || pertenece y c
  • elimina x vacio == vacio
  • Si x == y, entonces elimina x (inserta y c) == elimina x c
  • Si x /= y, entonces elimina x (inserta y c) == inserta y (elimina x c)
  • esVacio vacio
  • not (esVacio (inserta x c))

Leer más…

TAD de las colas - Reconocimiento de subcolas

Utilizando el tipo abstracto de datos de las colas, definir las funciones

   subCola :: Eq a => Cola a -> Cola a -> Bool

tal que subCola c1 c2 se verifica si c1 es una subcola de c2. Por ejemplo,

   λ> ej1 = inserta 2 (inserta 3 vacia)
   λ> ej2 = inserta 7 (inserta 2 (inserta 3 (inserta 5 vacia)))
   λ> ej3 = inserta 2 (inserta 7 (inserta 3 (inserta 5 vacia)))
   λ> subCola ej1 ej2
   True
   λ> subCola ej1 ej3
   False

Leer más…

TAD de las colas - Reconocimiento de prefijos de colas

Utilizando el tipo abstracto de datos de las colas, definir las funciones

   prefijoCola :: Eq a => Cola a -> Cola a -> Bool

tal que prefijoCola c1 c2 se verifica si la cola c1 es justamente un prefijo de la cola c2. Por ejemplo,

   λ> ej1 = inserta 4 (inserta 2 vacia)
   λ> ej2 = inserta 5 (inserta 4 (inserta 2 vacia))
   λ> ej3 = inserta 5 (inserta 2 (inserta 4 vacia))
   λ> prefijoCola ej1 ej2
   True
   λ> prefijoCola ej1 ej3
   False

Leer más…

TAD de las colas - Inclusión de colas

Utilizando el tipo abstracto de datos de las colas, definir las funciones

   contenidaCola :: Eq a => Cola a -> Cola a -> Bool

tal que contenidaCola c1 c2 se verifica si todos los elementos de la cola c1 son elementos de la cola c2. Por ejemplo,

   λ> ej1 = inserta 3 (inserta 2 vacia)
   λ> ej2 = inserta 3 (inserta 4 vacia)
   λ> ej3 = inserta 5 (inserta 2 (inserta 3 vacia))
   λ> contenidaCola ej1 ej3
   True
   λ> contenidaCola ej2 ej3
   False

Leer más…

TAD de las colas - Agrupación de colas

Utilizando el tipo abstracto de datos de las colas, definir las funciones

   agrupaColas :: [Cola a] -> Cola a

tal que agrupaColas [c1,c2,c3,...,cn] es la cola formada mezclando las colas de la lista como sigue: mezcla c1 con c2, el resultado con c3, el resultado con c4, y así sucesivamente. Por ejemplo,

   λ> ej1 = inserta 2 (inserta 5 vacia)
   λ> ej2 = inserta 3 (inserta 7 (inserta 4 vacia))
   λ> ej3 = inserta 9 (inserta 0 (inserta 1 (inserta 6 vacia)))
   λ> agrupaColas []
   -
   λ> agrupaColas [ej1]
   5 | 2
   λ> agrupaColas [ej1, ej2]
   5 | 4 | 2 | 7 | 3
   λ> agrupaColas [ej1, ej2, ej3]
   5 | 6 | 4 | 1 | 2 | 0 | 7 | 9 | 3

Leer más…

TAD de las colas - Intercalado de dos colas

Utilizando el tipo abstracto de datos de las colas, definir las funciones

   intercalaColas :: Cola a -> Cola a -> Cola a

tal que intercalaColas c1 c2 es la cola formada por los elementos de c1 y c2 colocados en una cola, de forma alternativa, empezando por los elementos de c1. Por ejemplo,

   λ> ej1 = inserta 3 (inserta 5 vacia)
   λ> ej2 = inserta 0 (inserta 7 (inserta 4 (inserta 9 vacia)))
   λ> intercalaColas ej1 ej2
   5 | 9 | 3 | 4 | 7 | 0
   λ> intercalaColas ej2 ej1
   9 | 5 | 4 | 3 | 7 | 0

Leer más…

TAD de las colas - Extensión de colas

Utilizando el tipo abstracto de datos de las colas, definir las funciones

   extiendeCola :: Cola a -> Cola a -> Cola a

tal que extiendeCola c1 c2 es la cola que resulta de poner los elementos de la cola c2 a continuación de los de la cola de c1. Por ejemplo,

   λ> ej1 = inserta 3 (inserta 2 vacia)
   λ> ej2 = inserta 5 (inserta 3 (inserta 4 vacia))
   λ> ej1
   2 | 3
   λ> ej2
   4 | 3 | 5
   λ> extiendeCola ej1 ej2
   2 | 3 | 4 | 3 | 5
   λ> extiendeCola ej2 ej1
   4 | 3 | 5 | 2 | 3

Leer más…

TAD de las colas - Alguno de los elementos verifican una propiedad

Utilizando el tipo abstracto de datos de las colas, definir las funciones

   algunoVerifica :: (a -> Bool) -> Cola a -> Bool

tal que algunoVerifica p c se verifica si alguno de los elementos de la cola c cumplen la propiedad p. Por ejemplo,

   algunoVerifica (< 0) (inserta 3 (inserta (-2) vacia)) == True
   algunoVerifica (< 0) (inserta 3 (inserta 2 vacia))    == False

Leer más…

TAD de las colas - Transformaciones entre colas y listas

Utilizando el tipo abstracto de datos de las colas, definir las funciones

   listaAcola :: [a] -> Cola a
   colaAlista :: Cola a -> [a]

tales que

  • listaAcola xs es la cola formada por los elementos de xs. Por ejemplo,
     λ> listaAcola [3, 2, 5]
     3 | 2 | 5
  • colaAlista c es la lista formada por los elementos de la cola c. Por ejemplo,
     λ> colaAlista (inserta 5 (inserta 2 (inserta 3 vacia)))
     [3, 2, 5]

Comprobar con QuickCheck que ambas funciones son inversa; es decir,

   colaAlista (listaAcola xs) = xs
   listaAcola (colaAlista c)  = c

Leer más…

El tipo abstracto de datos de las colas

1. El tipo abstracto de datos de las colas

Una cola es una estructura de datos, caracterizada por ser una secuencia de elementos en la que la operación de inserción se realiza por un extremo (el posterior o final) y la operación de extracción por el otro (el anterior o frente).

Las operaciones que definen a tipo abstracto de datos (TAD) de las colas (cuyos elementos son del tipo a) son las siguientes:

   vacia   :: Cola a
   inserta :: a -> Cola a -> Cola a
   primero :: Cola a -> a
   resto   :: Cola a -> Cola a
   esVacia :: Cola a -> Bool

tales que

  • vacia es la cola vacía.
  • (inserta x c) es la cola obtenida añadiendo x al final de c.
  • (primero c) es el primero de la cola c.
  • (resto c) es la cola obtenida eliminando el primero de c.
  • (esVacia c) se verifica si c es la cola vacía.

Las operaciones tienen que verificar las siguientes propiedades:

  • primero (inserta x vacia) == x
  • Si c es una cola no vacía, entonces primero (inserta x c) == primero c,
  • resto (inserta x vacia) == vacia
  • Si c es una cola no vacía, entonces resto (inserta x c) == inserta x (resto c)
  • esVacia vacia
  • not (esVacia (inserta x c))

Leer más…

TAD de las pilas - Ordenación de pilas por inserción

Utilizando el tipo abstracto de datos de las pilas, definir la función

   ordenaInserPila :: Ord a => Pila a -> Pila a

tal que ordenaInserPila p es la pila obtenida ordenando por inserción los los elementos de la pila p. Por ejemplo,

   λ> ordenaInserPila (apila 4 (apila 1 (apila 3 vacia)))
   1 | 3 | 4

Comprobar con QuickCheck que la pila (ordenaInserPila p) está ordenada.

Leer más…

TAD de las pilas - Reconocimiento de subpilas

Utilizando el tipo abstracto de datos de las pilas, definir las funciones

   subPila :: Eq a => Pila a -> Pila a -> Bool

tal que subPila p1 p2 se verifica si p1 es una subpila de p2. Por ejemplo,

   λ> ej1 = apila 2 (apila 3 vacia)
   λ> ej2 = apila 7 (apila 2 (apila 3 (apila 5 vacia)))
   λ> ej3 = apila 2 (apila 7 (apila 3 (apila 5 vacia)))
   λ> subPila ej1 ej2
   True
   λ> subPila ej1 ej3
   False

Leer más…

TAD de las pilas - Reconocimiento de prefijos de pilas

Utilizando el tipo abstracto de datos de las pilas, definir las funciones

   prefijoPila :: Eq a => Pila a -> Pila a -> Bool

tal que prefijoPila p1 p2 se verifica si la pila p1 es justamente un prefijo de la pila p2. Por ejemplo,

   λ> ej1 = apila 4 (apila 2 vacia)
   λ> ej2 = apila 4 (apila 2 (apila 5 vacia))
   λ> ej3 = apila 5 (apila 4 (apila 2 vacia))
   λ> prefijoPila ej1 ej2
   True
   λ> prefijoPila ej1 ej3
   False

Leer más…

TAD de las pilas - Inclusión de pilas

Utilizando el tipo abstracto de datos de las pilas, definir las funciones

   contenidaPila :: Eq a => Pila a -> Pila a -> Bool

tal que contenidaPila p1 p2 se verifica si todos los elementos de de la pila p1 son elementos de la pila p2. Por ejemplo,

   λ> ej1 = apila 3 (apila 2 vacia)
   λ> ej2 = apila 3 (apila 4 vacia)
   λ> ej3 = apila 5 (apila 2 (apila 3 vacia))
   λ> contenidaPila ej1 ej3
   True
   λ> contenidaPila ej2 ej3
   False

Leer más…

TAD de las pilas - Filtrado de pilas según una propiedad

Utilizando el tipo abstracto de datos de las pilas, definir las funciones

   filtraPila :: (a -> Bool) -> Pila a -> Pila a

tal que filtraPila p q es la pila obtenida con los elementos de pila q que verifican el predicado p, en el mismo orden. Por ejemplo,

   λ> ejPila = apila 6 (apila 3 (apila 1 (apila 4 vacia)))
   λ> ejPila
   6 | 3 | 1 | 4
   λ> filtraPila even ejPila
   6 | 4
   λ> filtraPila odd ejPila
   3 | 1

Leer más…

TAD de las pilas - Transformaciones entre pilas y listas

Utilizando el tipo abstracto de datos de las pilas, definir las funciones

   listaApila :: [a] -> Pila a
   pilaALista :: Pila a -> [a]

tales que

  • listaApila xs es la pila formada por los elementos de xs. Por ejemplo,
     λ> listaApila [3, 2, 5]
     5 | 2 | 3
 ~~~
+ `pilaALista p` es la lista formada por los elementos de la lista `p`. Por ejemplo,
~~~haskell
     λ> pilaAlista (apila 5 (apila 2 (apila 3 vacia)))
     [3, 2, 5]

Comprobar con QuickCheck que ambas funciones son inversa; es decir,

   pilaAlista (listaApila xs) == xs
   listaApila (pilaAlista p)  == p

Leer más…

El tipo abstracto de datos de las pilas

1. El tipo abstracto de datos de las pilas

Una pila es una estructura de datos, caracterizada por ser una secuencia de elementos en la que las operaciones de inserción y extracción se realizan por el mismo extremo.

Las operaciones que definen a tipo abstracto de datos (TAD) de las pilas (cuyos elementos son del tipo a) son las siguientes:

   vacia    :: Pila a
   apila    :: a -> Pila a -> Pila a
   cima     :: Pila a -> a
   desapila :: Pila a -> Pila a
   esVacia  :: Pila a -> Bool

tales que

  • vacia es la pila vacía.
  • (apila x p) es la pila obtenida añadiendo x al principio de p.
  • (cima p) es la cima de la pila p.
  • (desapila p) es la pila obtenida suprimiendo la cima de p.
  • (esVacia p) se verifica si p es la pila vacía.

Las operaciones tienen que verificar las siguientes propiedades:

  • cima(apila(x, p) == x
  • desapila(apila(x, p)) == p
  • esVacia(vacia)
  • not esVacia(apila(x, p))

Leer más…

Valor de una expresión vectorial

Se consideran las expresiones vectoriales formadas por un vector, la suma de dos expresiones vectoriales o el producto de un entero por una expresión vectorial. El siguiente tipo de dato define las expresiones vectoriales

   data ExpV = Vec Int Int
             | Sum ExpV ExpV
             | Mul Int ExpV
     deriving Show

Definir la función

   valorEV :: ExpV -> (Int,Int)

tal que valorEV e es el valorEV de la expresión vectorial e. Por ejemplo,

   valorEV (Vec 1 2)                                  ==  (1,2)
   valorEV (Sum (Vec 1 2) (Vec 3 4))                  ==  (4,6)
   valorEV (Mul 2 (Vec 3 4))                          ==  (6,8)
   valorEV (Mul 2 (Sum (Vec 1 2 ) (Vec 3 4)))         ==  (8,12)
   valorEV (Sum (Mul 2 (Vec 1 2)) (Mul 2 (Vec 3 4)))  ==  (8,12)

Leer más…

Valor de expresiones aritméticas generales

Las operaciones de suma, resta y multiplicación se pueden representar mediante el siguiente tipo de datos

   data Op = S | R | M

La expresiones aritméticas con dichas operaciones se pueden representar mediante el siguiente tipo de dato algebraico

   data Expr = C Int
             | A Op Expr Expr

Por ejemplo, la expresión

   (7-3)+(2*5)

se representa por

   A S (A R (C 7) (C 3)) (A M (C 2) (C 5))

Definir la función

   valor :: Expr -> Int

tal que valor e es el valor de la expresión e. Por ejemplo,

   valor (A S (A R (C 7) (C 3)) (A M (C 2) (C 5)))  ==  14
   valor (A M (A R (C 7) (C 3)) (A S (C 2) (C 5)))  ==  28

Leer más…

Máximos valores de una expresión aritmética

Las expresiones aritméticas generales se pueden definir usando el siguiente tipo de datos

   data Expr = C Int
             | X
             | S Expr Expr
             | R Expr Expr
             | P Expr Expr
             | E Expr Int
     deriving (Eq, Show)

Por ejemplo, la expresión

   3*x - (x+2)^7

se puede definir por

   R (P (C 3) X) (E (S X (C 2)) 7)

Definir la función

   maximo :: Expr -> [Int] -> (Int,[Int])

tal que maximo e xs es el par formado por el máximo valor de la expresión e para los puntos de xs y en qué puntos alcanza el máximo. Por ejemplo,

   λ> maximo (E (S (C 10) (P (R (C 1) X) X)) 2) [-3..3]
   (100,[0,1])

Leer más…

Expresiones aritméticas reducibles

Las expresiones aritméticas con variables pueden representarse usando el siguiente tipo de datos

   data Expr = C Int
             | V Char
             | S Expr Expr
             | P Expr Expr

Por ejemplo, la expresión 2·(a+5) se representa por

   P (C 2) (S (V 'a') (C 5))

Definir la función

   reducible :: Expr -> Bool

tal que reducible a se verifica si a es una expresión reducible; es decir, contiene una operación en la que los dos operandos son números. Por ejemplo,

   reducible (S (C 3) (C 4))             == True
   reducible (S (C 3) (V 'x'))           == False
   reducible (S (C 3) (P (C 4) (C 5)))   == True
   reducible (S (V 'x') (P (C 4) (C 5))) == True
   reducible (S (C 3) (P (V 'x') (C 5))) == False
   reducible (C 3)                       == False
   reducible (V 'x')                     == False

Leer más…

Sustitución en una expresión aritmética

Las expresiones aritméticas con variables pueden representarse usando el siguiente tipo de datos

   data Expr = C Int
             | V Char
             | S Expr Expr
             | P Expr Expr
     deriving (Eq, Show)

Por ejemplo, la expresión 2·(a+5) se representa por

   P (C 2) (S (V 'a') (C 5))

Definir la función

   sustitucion :: Expr -> [(Char, Int)] -> Expr

tal que sustitucion e s es la expresión obtenida sustituyendo las variables de la expresión e según se indica en la sustitución s. Por ejemplo,

   λ> sustitucion (P (V 'z') (S (C 3) (V 'x'))) [('x',7),('z',9)]
   P (C 9) (S (C 3) (C 7))
   λ> sustitucion (P (V 'z') (S (C 3) (V 'y'))) [('x',7),('z',9)]
   P (C 9) (S (C 3) (V 'y'))

Leer más…

Número de sumas en una expresión aritmética

Las expresiones aritméticas con variables pueden representarse usando el siguiente tipo de datos

   data Expr = C Int
             | V Char
             | S Expr Expr
             | P Expr Expr

Por ejemplo, la expresión 2·(a+5) se representa por

   P (C 2) (S (V 'a') (C 5))

Definir la función

   sumas :: Expr -> Int

tal que sumas e es el número de sumas en la expresión e. Por ejemplo,

   sumas (P (V 'z') (S (C 3) (V 'x')))  ==  1
   sumas (S (V 'z') (S (C 3) (V 'x')))  ==  2
   sumas (P (V 'z') (P (C 3) (V 'x')))  ==  0

Leer más…

Valor de una expresión aritmética con variables

Las expresiones aritméticas con variables pueden representarse usando el siguiente tipo de datos

   data Expr = C Int
             | V Char
             | S Expr Expr
             | P Expr Expr

Por ejemplo, la expresión 2·(a+5) se representa por

   P (C 2) (S (V 'a') (C 5))

Definir la función

   valor :: Expr -> [(Char,Int)] -> Int

tal que valor x e es el valor de la expresión x en el entorno e (es decir, el valor de la expresión donde las variables de x se sustituyen por los valores según se indican en el entorno e). Por ejemplo,

   λ> valor (P (C 2) (S (V 'a') (V 'b'))) [('a',2),('b',5)]
   14

Leer más…

El tipo de las expresiones aritméticas con variables

1. El tipo de las expresiones aritméticas con variables en Haskell

La expresión 2*(a+5) puede representarse por

   P (C 2) (S (V 'a') (C 5))

usando el tipo de las expresiones aritméticas con variables definido como se muestra a continuación.

module Expresion_aritmetica_con_variables where

data Expr = C Int
          | V Char
          | S Expr Expr
          | P Expr Expr

2. El tipo de las expresiones aritméticas con variables en Python

La expresión 2*(a+5) puede representarse por

   P(C(2), S(V('a'), C(5)))

usando el tipo de las expresiones aritméticas con variables definido como se muestra a continuación.

from dataclasses import dataclass


@dataclass
class Expr:
    pass

@dataclass
class C(Expr):
    x: int

@dataclass
class V(Expr):
    x: str

@dataclass
class S(Expr):
    x: Expr
    y: Expr

@dataclass
class P(Expr):
    x: Expr
    y: Expr

Número de variables de una expresión aritmética

Las expresiones aritméticas construidas con una variable (denotada por X), los números enteros y las operaciones de sumar y multiplicar se pueden representar mediante el tipo de datos Expr definido por

   data Expr = X
             | C Int
             | S Expr Expr
             | P Expr Expr

Por ejemplo, la expresión X·(13+X) se representa por

   P X (S (C 13) X)

Definir la función

   numVars :: Expr -> Int

tal que numVars e es el número de variables en la expresión e. Por ejemplo,

   numVars (C 3)               ==  0
   numVars X                   ==  1
   numVars (P X (S (C 13) X))  ==  2

Leer más…

Valor de una expresión aritmética con una variable

Las expresiones aritméticas construidas con una variable (denotada por X), los números enteros y las operaciones de sumar y multiplicar se pueden representar mediante el tipo de datos Expr definido por

   data Expr = X
             | C Int
             | S Expr Expr
             | P Expr Expr

Por ejemplo, la expresión X·(13+X) se representa por

   P X (S (C 13) X)

Definir la función

   valor :: Expr -> Int -> Int

tal que valor e n es el valor de la expresión e cuando se sustituye su variable por n. Por ejemplo,

   valor (P X (S (C 13) X)) 2  ==  30

Leer más…

Tipo de expresiones aritméticas con una variable

1. El tipo de las expresiones aritméticas con una variable en Haskell

La expresión X·(13+X) se representa por

   P(X(), S(C(13), X()))

usando el tipo de las expresiones aritméticas con una variable (denotada por X) que se define como se muestra a continuación,

data Expr = C Int
          | V Char
          | S Expr Expr
          | P Expr Expr

2. El tipo de las expresiones aritméticas con una variable en Python

La expresión X*(13+X) se representa por

   P(X(), S(C(13), X()))

usando el tipo de las expresiones aritméticas con una variable (denotada por X) que se define como se muestra a continuación,

from dataclasses import dataclass


@dataclass
class Expr:
    pass

@dataclass
class X(Expr):
    pass

@dataclass
class C(Expr):
    x: int

@dataclass
class S(Expr):
    x: Expr
    y: Expr

@dataclass
class P(Expr):
    x: Expr
    y: Expr

Aplicación de una función a una expresión aritmética

Usando el tipo de las expresiones aritméticas básicas, definir la función

   aplica :: (Int -> Int) -> Expr -> Expr

tal que aplica f e es la expresión obtenida aplicando la función f a cada uno de los números de la expresión e. Por ejemplo,

   λ> aplica (+2) (S (P (C 3) (C 5)) (P (C 6) (C 7)))
   S (P (C 5) (C 7)) (P (C 8) (C 9))
   λ> aplica (*2) (S (P (C 3) (C 5)) (P (C 6) (C 7)))
   S (P (C 6) (C 10)) (P (C 12) (C 14))

Leer más…

El tipo de las expresiones aritméticas básicas

1. El tipo de las expresiones aritméticas básicas en Haskell

La expresión aritmética 2*(3+7) se representa por

   P (C 2) (S (C 3) (C 7))

usando el tipo de dato definido a continuación.

module Expresion_aritmetica_basica where

data Expr = C Int
          | S Expr Expr
          | P Expr Expr

2. El tipo de las expresiones aritméticas básicas en Python

La expresión aritmética 2*(3+7) se representa por

   P(C(2), S(C(3), C(7)))

usando el tipo de dato definido a continuación.

from dataclasses import dataclass


@dataclass
class Expr:
    pass

@dataclass
class C(Expr):
    x: int

@dataclass
class S(Expr):
    x: Expr
    y: Expr

@dataclass
class P(Expr):
    x: Expr
    y: Expr

Valor de un árbol booleano

Se consideran los árboles con operaciones booleanas definidos por

   data Arbol = H Bool
              | Conj Arbol Arbol
              | Disy Arbol Arbol
              | Neg Arbol

Por ejemplo, los árboles

               Conj                            Conj
              /   \                           /   \
             /     \                         /     \
          Disy      Conj                  Disy      Conj
         /   \       /  \                /   \      /   \
      Conj    Neg   Neg True          Conj    Neg   Neg  True
      /  \    |     |                 /  \    |     |
   True False False False          True False True  False

se definen por

   ej1, ej2:: Arbol
   ej1 = Conj (Disy (Conj (H True) (H False))
                    (Neg (H False)))
              (Conj (Neg (H False))
                    (H True))

   ej2 = Conj (Disy (Conj (H True) (H False))
                    (Neg (H True)))
              (Conj (Neg (H False))
                    (H True))

Definir la función

   valor :: Arbol -> Bool

tal que valor a) es el resultado de procesar el árbol a realizando las operaciones booleanas especificadas en los nodos. Por ejemplo,

   valor ej1 == True
   valor ej2 == False

Leer más…

Árbol de factorización

Los divisores medios de un número son los que ocupan la media entre los divisores de n, ordenados de menor a mayor. Por ejemplo, los divisores de 60 son [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60] y sus divisores medios son 6 y 10. Para los números que son cuadrados perfectos, sus divisores medios de son sus raíces cuadradas; por ejemplos, los divisores medios de 9 son 3 y 3.

El árbol de factorización de un número compuesto n se construye de la siguiente manera:

  • la raíz es el número n,
  • la rama izquierda es el árbol de factorización de su divisor medio menor y
  • la rama derecha es el árbol de factorización de su divisor medio mayor

Si el número es primo, su árbol de factorización sólo tiene una hoja con dicho número. Por ejemplo, el árbol de factorización de 60 es

       60
      /  \
     6    10
    / \   / \
   2   3 2   5

Definir la función

   arbolFactorizacion :: Int -> Arbol

tal que arbolFactorizacion n es el árbol de factorización de n. Por ejemplo,

   arbolFactorizacion 60 == N 60 (N 6 (H 2) (H 3)) (N 10 (H 2) (H 5))
   arbolFactorizacion 45 == N 45 (H 5) (N 9 (H 3) (H 3))
   arbolFactorizacion 7  == H 7
   arbolFactorizacion 9  == N 9 (H 3) (H 3)
   arbolFactorizacion 14 == N 14 (H 2) (H 7)
   arbolFactorizacion 28 == N 28 (N 4 (H 2) (H 2)) (H 7)
   arbolFactorizacion 84 == N 84 (H 7) (N 12 (H 3) (N 4 (H 2) (H 2)))

Leer más…

Elementos del nivel k de un árbol

Los árboles binarios con valores en las hojas y en los nodos se definen por

   data Arbol a = H a
                | N a (Arbol a) (Arbol a)

Por ejemplo, el árbol

        7
       / \
      /   \
     2     9
    / \
   5   4

se representa por

   N 7 (N 2 (H 5) (H 4)) (H 9)

Un elemento de un árbol se dirá de nivel k si aparece en el árbol a distancia k de la raíz.

Definir la función

   nivel :: Int -> Arbol a -> [a]

tal que nivel k a es la lista de los elementos de nivel k del árbol a. Por ejemplo,

   nivel 0 (N 7 (N 2 (H 5) (H 4)) (H 9))  ==  [7]
   nivel 1 (N 7 (N 2 (H 5) (H 4)) (H 9))  ==  [2,9]
   nivel 2 (N 7 (N 2 (H 5) (H 4)) (H 9))  ==  [5,4]
   nivel 3 (N 7 (N 2 (H 5) (H 4)) (H 9))  ==  []

Leer más…

Existencia de elementos del árbol que verifican una propiedad

Los árboles binarios con valores en las hojas y en los nodos se definen por

   data Arbol a = H a
                | N a (Arbol a) (Arbol a)
     deriving Show

Por ejemplo, el árbol

        5
       / \
      /   \
     3     2
    / \
   1   4

se representa por

   N 5 (N 3 (H 1) (H 4)) (H 2)

Definir la función

   algunoArbol :: Arbol t -> (t -> Bool) -> Bool

tal que algunoArbol a p se verifica si algún elemento del árbol a cumple la propiedad p. Por ejemplo,

   algunoArbol (N 5 (N 3 (H 1) (H 4)) (H 2)) (>4)  ==  True
   algunoArbol (N 5 (N 3 (H 1) (H 4)) (H 2)) (>7)  ==  False

Leer más…

Árboles con igual estructura

Los árboles binarios con valores en las hojas y en los nodos se definen por

   data Arbol a = H a
                | N a (Arbol a) (Arbol a)
     deriving Show

Por ejemplo, los árboles

        5              8             5           5
       / \            / \           / \         / \
      /   \          /   \         /   \       /   \
     9     7        9     3       9     2     4     7
    / \   / \      / \   / \     / \               / \
   1   4 6   8    1   4 6   2   1   4             6   2

se pueden representar por

   ej3arbol1, ej3arbol2, ej3arbol3, ej3arbol4 :: Arbol Int
   ej3arbol1 = N 5 (N 9 (H 1) (H 4)) (N 7 (H 6) (H 8))
   ej3arbol2 = N 8 (N 9 (H 1) (H 4)) (N3 3 (H 6) (H 2))
   ej3arbol3 = N 5 (N 9 (H 1) (H 4)) (H 2)
   ej3arbol4 = N 5 (H 4) (N 7 (H 6) (H 2))

Definir la función

   igualEstructura :: Arbol -> Arbol -> Bool

tal que igualEstructura a1 a2 se verifica si los árboles a1 y a2 tienen la misma estructura. Por ejemplo,

   igualEstructura ej3arbol1 ej3arbol2 == True
   igualEstructura ej3arbol1 ej3arbol3 == False
   igualEstructura ej3arbol1 ej3arbol4 == False

Leer más…

Árboles con bordes iguales

Los árboles binarios con valores en las hojas se pueden definir por

   data Arbol a = H a
                | N (Arbol a) (Arbol a)
     deriving Show

Por ejemplo, los árboles

   árbol1          árbol2       árbol3     árbol4
      o              o           o           o
     / \            / \         / \         / \
    1   o          o   3       o   3       o   1
       / \        / \         / \         / \
      2   3      1   2       1   4       2   3

se representan por

   arbol1, arbol2, arbol3, arbol4 :: Arbol Int
   arbol1 = N (H 1) (N (H 2) (H 3))
   arbol2 = N (N (H 1) (H 2)) (H 3)
   arbol3 = N (N (H 1) (H 4)) (H 3)
   arbol4 = N (N (H 2) (H 3)) (H 1)

Definir la función

   igualBorde :: Eq a => Arbol a -> Arbol a -> Bool

tal que igualBorde t1 t2 se verifica si los bordes de los árboles t1 y t2 son iguales. Por ejemplo,

   igualBorde arbol1 arbol2  ==  True
   igualBorde arbol1 arbol3  ==  False
   igualBorde arbol1 arbol4  ==  False

Leer más…

Árboles balanceados

Los árboles binarios con valores en los nodos se pueden definir por

   data Arbol a = H
                | N a (Arbol a) (Arbol a)
     deriving (Show, Eq)

Por ejemplo, el árbol

        9
       / \
      /   \
     8     6
    / \   / \
   3   2 4   5

se puede representar por

   N 9 (N 8 (N 3 H H) (N 2 H H)) (N 6 (N 4 H H) (N 5 H H))

Diremos que un árbol está balanceado si para cada nodo la diferencia entre el número de nodos de sus subárboles izquierdo y derecho es menor o igual que uno.

Definir la función

   balanceado :: Arbol a -> Bool

tal que (balanceado a) se verifica si el árbol a está balanceado. Por ejemplo,

   λ> balanceado (N 5 H (N 3 H H))
   True
   λ> balanceado (N 4 (N 3 (N 2 H H) H) (N 5 H (N 6 H (N 7 H H))))
   False

Leer más…

Rama izquierda de un árbol binario.

Los árboles binarios con valores en los nodos se pueden definir por

   data Arbol a = H
                | N a (Arbol1 a) (Arbol1 a)
     deriving (Show, Eq)

Por ejemplo, el árbol

        9
       / \
      /   \
     8     6
    / \   / \
   3   2 4   5

se puede representar por

   N 9 (N 8 (N 3 H H) (N 2 H H)) (N 6 (N 4 H H) (N 5 H H))

Definir la función

   ramaIzquierda :: Arbol a -> [a]

tal que ramaIzquierda a es la lista de los valores de los nodos de la rama izquierda del árbol a. Por ejemplo,

   λ> ramaIzquierda (N 2 (N 5 (N 3 H H) (N 7 H H)) (N 4 H H))
   [2,5,3]

<!-- TEASER_END -->~~~
# Soluciones

A continuación se muestran las [soluciones en Haskell](#haskell) y las [soluciones en Python](#python).

<a name="haskell"></a>
## Soluciones en Haskell

~~~haskell
data Arbol a = H
             | N a (Arbol a) (Arbol a)
  deriving (Show, Eq)

ramaIzquierda :: Arbol a -> [a]
ramaIzquierda H         = []
ramaIzquierda (N x i _) = x : ramaIzquierda i

Soluciones en Python

from dataclasses import dataclass
from typing import Generic, TypeVar

A = TypeVar("A")

@dataclass
class Arbol(Generic[A]):
    pass

@dataclass
class H(Arbol[A]):
    pass

@dataclass
class N(Arbol[A]):
    x: A
    i: Arbol[A]
    d: Arbol[A]

def ramaIzquierda(a: Arbol[A]) -> list[A]:
    match a:
        case H():
            return []
        case N(x, i, _):
            return [x] + ramaIzquierda(i)
    assert False

Suma de un árbol

Los árboles binarios con valores en los nodos se pueden definir por

   data Arbol a = H
                | N a (Arbol1 a) (Arbol1 a)
     deriving (Show, Eq)

Por ejemplo, el árbol

        9
       / \
      /   \
     8     6
    / \   / \
   3   2 4   5

se puede representar por

   N 9 (N 8 (N 3 H H) (N 2 H H)) (N 6 (N 4 H H) (N 5 H H))

Definir por recursión la función

   sumaArbol :: Num a => Arbol1 a -> a

tal sumaArbol x es la suma de los valores que hay en el árbol x. Por ejemplo,

   sumaArbol (N 2 (N 5 (N 3 H H) (N 7 H H)) (N 4 H H)) == 21

Leer más…

El tipo de los árboles binarios con valores en los nodos

1. El tipo de los árboles binarios con valores en los nodos en Haskell

El árbol, con valores en los nodos,

           9
          / \
         /   \
        /     \
       8       6
      / \     / \
     3   2   4   5
    /\  /\  /\   /\
   ·  ··  ··  · ·  ·

se puede representar por

   N 9 (N 8 (N 3 H H) (N 2 H H)) (N 6 (N 4 H H) (N 5 H H))

usando el tipo de los árboles con valores en los nodos definido como se muestra a continuación.

data Arbol a = H
             | N a (Arbol a) (Arbol a)
  deriving (Show, Eq)

2. El tipo de los árboles binarios con valores en los nodos en Python

El árbol binario, con valores en los nodos,

           9
          / \
         /   \
        /     \
       8       6
      / \     / \
     3   2   4   5
    /\  /\  /\   /\
   ·  ··  ··  · ·  ·

se puede representar por

   N(9, N(8, N(3, H(), H()), N(2, H(), H())), N(6, N(4, H(), H()), N(5, H(), H())))

usando el tipo de los árboles binarios con valores en los nodos definido como se muestra a continuación.

from dataclasses import dataclass


@dataclass
class Arbol:
    pass

@dataclass
class H(Arbol):
    pass

@dataclass
class N(Arbol):
    x: int
    i: Arbol
    d: Arbol

Árbol de profundidad n con nodos iguales

El árbol binario

        9
       / \
      /   \
     3     7
    / \
   2   4

se puede representar por

   N 9 (N 3 (H 2) (H 4)) (H 7)

El tipo de los árboles binarios se puede definir por

   data Arbol a = H a
                | N a (Arbol a) (Arbol a)
     deriving (Show, Eq)

Definir las funciones

   repeatArbol    :: a -> Arbol a
   replicateArbol :: Int -> a -> Arbol a

tales que

  • repeatArbol x es es árbol con infinitos nodos x. Por ejemplo,
     takeArbol 0 (repeatArbol 3) == H 3
     takeArbol 1 (repeatArbol 3) == N 3 (H 3) (H 3)
     takeArbol 2 (repeatArbol 3) == N 3 (N 3 (H 3) (H 3)) (N 3 (H 3) (H 3))
  • replicate n x es el árbol de profundidad n cuyos nodos son x. Por ejemplo,
     replicateArbol 0 5  ==  H 5
     replicateArbol 1 5  ==  N 5 (H 5) (H 5)
     replicateArbol 2 5  ==  N 5 (N 5 (H 5) (H 5)) (N 5 (H 5) (H 5))

Leer más…

Subárbol de profundidad dada

El árbol binario

        9
       / \
      /   \
     3     7
    / \
   2   4

se puede representar por

   N 9 (N 3 (H 2) (H 4)) (H 7)

El tipo de los árboles binarios se puede definir por

   data Arbol a = H a
                | N a (Arbol a) (Arbol a)
     deriving (Show, Eq)

La función take está definida por

   take :: Int -> [a] -> [a]
   take 0            = []
   take (n+1) []     = []
   take (n+1) (x:xs) = x : take n xs

Definir la función

   takeArbol ::  Int -> Arbol a -> Arbol a

tal que takeArbol n t es el subárbol de t de profundidad n. Por ejemplo,

   takeArbol 0 (N 9 (N 3 (H 2) (H 4)) (H 7)) == H 9
   takeArbol 1 (N 9 (N 3 (H 2) (H 4)) (H 7)) == N 9 (H 3) (H 7)
   takeArbol 2 (N 9 (N 3 (H 2) (H 4)) (H 7)) == N 9 (N 3 (H 2) (H 4)) (H 7)
   takeArbol 3 (N 9 (N 3 (H 2) (H 4)) (H 7)) == N 9 (N 3 (H 2) (H 4)) (H 7)

Comprobar con QuickCheck que la profundidad de takeArbol n x es menor o igual que n, para todo número natural n y todo árbol x.

Leer más…

Imagen especular de un árbol binario

El árbol binario

        9
       / \
      /   \
     3     7
    / \
   2   4

se puede representar por

   N 9 (N 3 (H 2) (H 4)) (H 7)

El tipo de los árboles binarios se puede definir por

   data Arbol a = H a
                | N a (Arbol a) (Arbol a)
     deriving (Show, Eq)

Definir la función

   espejo :: Arbol a -> Arbol a

tal que espejo x es la imagen especular del árbol x. Por ejemplo,

   espejo (N 9 (N 3 (H 2) (H 4)) (H 7)) == N 9 (H 7) (N 3 (H 4) (H 2))

Comprobar con QuickCheck las siguientes propiedades, para todo árbol x,

   espejo (espejo x) = x
   reverse (preorden (espejo x)) = postorden x
   postorden (espejo x) = reverse (preorden x)

Leer más…