Altenwald Blog
Blog sobre programación, software libre, redes, servidores, ...
Menú
Acerca de... ¿Quiénes somos? RSS
Categorías
sistemas (70) desarrollo (128) historias (25) productividad (49) seguridad (10) libros (25) noticias (45) opinión (35) humor (3)
Etiquetas
programación (111) desarrollo de software (79) erlang (75) opinión (37) noticia (36) libros (28) servidores (26) desarrollo web (24) base de datos (24) administración de sistemas (23) php (22) desarrollo ágil (22) empresa (21) otp (20) ruby (19) ingeniería de negocio (18) elixir (18) desarrollo profesional (16) redes (16) seguridad (14)
2018-09-19
4 min desarrollo
Montículos con Elixir
[ programación ]  [ heap ]  [ heapsort ]  [ montículos ]  [ priorityqueue ]  [ robert floyd ]  [ uned ]  [ elixir ] 

Hace 7 años escribí una entrada mientras estudiaba los montículos para la asignatura de Programación y Estructuras de Datos Avanzadas de la UNED. Al revisar la entrada y ver que aún hay mucha gente consultando he decidido retomarla y actualizarla pero además he creado esta entrada para ver cómo se haría en Elixir, ¿te animas a ver los montículos en Elixir?

Prefiero que leáis la otra entrada para todo el tema teórico sobre los montículos y centrar esta entrada solo en la parte que concierne a Elixir. Solo comentaré de los montículos la definición.

Un montículo es un árbol binario balanceado que cumple con la premisa de que: ningún padre tiene un hijo mayor (montículo de máximos) o menor (montículo de mínimos) a él. Una definición corta y concreta, ¿no?

El montículo, aunque conceptualmente se dibuja en forma de árbol, está implementado sobre un vector. Ya que es balanceado y binario, un nodo solo puede contener dos hijos. La formula para acceder a cada hijo, dado el índice del padre (i), sería:

hijo_izquierdo = 2i
hijo_derecho = 2i + 1

El acceso al padre se realizaría con una división entera: i / 2.

Implementación del algoritmo

El código base para el módulo empleando Elixir sería:

defmodule MonticuloMaximos do
end

Ahora vamos a ir creando las funciones para agregarlas dentro de esa especificación:

def nuevo, do: []
def vacio?(monticulo) do
  monticulo == []
end
def insertar(monticulo, elemento) do
  insertar(monticulo, [], elemento)
end

def insertar([], elementos, elemento), do: elementos ++ [elemento]
def insertar([a1|a], elementos, elemento) when a1 > elemento do
  insertar(a, elementos ++ [a1], elemento)
end
def insertar(a, elementos, elemento) do
  elementos ++ [elemento|a]
end
def primero([elemento|_]), do: elemento
def cima([elemento|monticulo]), do: {elemento, monticulo}

Una vez visto todo el código, podemos hacer una prueba como la siguiente, en la que insertaremos unos datos aleatorios y obtendremos el resultado de su almacenamiento en forma de montículo, y el resultado en un vector ordenado:

iex> a = [ 6, 4, 3, 1, 5, 2, 4 ]
[ 6, 4, 3, 1, 5, 2, 4 ]

iex> m = MonticuloMaximos.nuevo
[]

iex> f = fn(e, m) ->
...>   MonticuloMaximos.insertar(m, e)
...> end
#Function<12.99386804/2 in :erl_eval.expr/5>

iex> List.foldl(a, m, f)
[6, 5, 4, 4, 3, 2, 1]

En esta versión no necesitamos de extraer o presentar la información. Está implementada usando una lista y eso nos da la ventaja de poder imprimirla por pantalla en la consola simplemente poniendo el valor o dentro de un texto con el uso de inspect.

Conclusiones

Realmente si queremos seguir las indicaciones del libro de texto que enseña a programar en lenguajes imperativos nos encontraremos ciertas contradicciones o puntos de inflexión donde los algoritmos no funcionan tal y como vienen expuestos. Comentaré algo en un futuro cercano. Por el momento me quedo con la simplicidad de ver cómo el código escrito en Elixir es igual de funcional que el escrito en Ruby y mucho más corto y manejable.

¿Y tú? ¿Has jugado con algoritmos básicos o de estructuras de datos entendidas para lenguajes imperativos en lenguajes funcionales? ¿Has tenido alguna experiencia buena o mala con el cambio? ¡Déjanos tu comentario!

Autor
Manuel Rubio
Programación Concurrente & Erlanger