Tema 4: Procedimientos y estructuras recursivas

Tamaño: px
Comenzar la demostración a partir de la página:

Download "Tema 4: Procedimientos y estructuras recursivas"

Transcripción

1 Tema 4: Procedimientos y estructuras recursivas Contenidos 1. Recursión 1.1 Pensando recursivamente 1.2 El coste de la recursión 1.3 Soluciones al coste de la recursión: procesos iterativos 1.4 Soluciones al coste de la recursión: memoization 2. Listas estructuradas 2.1. Definición y ejemplos 2.2. Pseudo árboles con niveles 2.3. Funciones recursivas sobre listas estructuradas 2.4. Ejercicios 3. Datos funcionales y barreras de abstracción 3.1. Datos funcionales 3.2. Barrera de abstracción 3.3. Números racionales 4. Árboles binarios 4.1. Barrera de abstracción 4.2. Funciones recursivas 5. Árboles genéricos 5.1. Barrera de abstracción 5.2. Funciones recursivas 5.3. Ejercicios 1. Recursión Ya hemos visto algunos ejemplos de funciones recursivas. Una función es recursiva cuando se llama a si misma. Una vez que uno se acostumbra a su uso, se comprueba que la recursión es

2 una forma mucho más natural que la iteración de expresar un gran número de funciones y procedimientos. Recordemos un ejemplo típico, el de longitud de una lista (define (longitud lista) (if (null? lista) 0 (+ 1 (longitud (cdr lista))))) La formulación matemática de la recursión es sencilla de entender, pero su implementación en un lenguaje de programación no lo es tanto. El primer lenguaje de programación que permitió el uso de expresiones recursivas fue el Lisp. En el momento de su creación existía ya el Fortran, que no permitía que una función se llamase a si misma. En la clase de hoy veremos cómo diseñar procedimientos recursivos y cuál es el coste espacial y temporal de la recursión. Más adelante comprobaremos que no siempre una función recursiva tiene un comportamiento recursivo, sino que hay casos en los que genera un proceso iterativo. En las siguientes clases del tema veremos que la recursión no sólo se utiliza para definir funciones y procedimientos sino que existen estructuras de datos cuya definición es recursiva, como las listas o los árboles Pensando recursivamente Para diseñar procedimientos recursivos no vale intentarlo resolver por prueba y error. Hay que diseñar la solución recursiva desde el principio. Debemos fijarnos en lo que devuelve la función y debemos preguntarnos cómo sería posible descomponer el problema de forma que podamos lanzar la recursión sobre una versión más sencilla del mismo. Supondremos que la llamada recursiva funciona correctamente y devuelve el resultado correcto. Y después debemos transformar este resultado correcto de la versión más pequeña en el resultado de la solución completa. Es muy importante escribir y pensar en las funciones de forma declarativa, teniendo en cuenta lo que hacen y no cómo lo hacen. Debes confiar en que la llamada recursiva va a hacer su trabajo y devolver el resultado correcto, sin preocuparte de cómo lo va a hacer. Después tendrás que utilizar lo que la llamada recursiva ha devuelto para componer la solución definitiva al problema. Para diseñar un algoritmo recursivo es útil no ponerse a programar directamente, sino

3 reflexionar sobre la solución recursiva con algún ejemplo. El objetivo es obtener una formulación abstracta del caso general de la recursión antes de programarlo. Una vez que encontramos esta formulación, pasarlo a un lenguaje de programación es muy sencillo. Por último, deberemos reflexionar en el caso base. Debe ser el caso más sencillo que puede recibir como parámetro la recursión. Debe devolver un valor compatible con la definición de la función. Por ejemplo, si la función debe construir una lista, el caso base debe devolver también una lista. Si la función construye una pareja, el caso base también devolverá una pareja. No debemos olvidar que el caso base es también un ejemplo de invocación de la función Longitud de una lista Empecemos con un sencillo ejemplo, la definición de la longitud de una lista. Cómo definir la longitud de una lista en términos recursivos? Tenemos que pensar: Si puedo calcular la longitud de una cadena más pequeña, cómo puedo calcular la longitud de la cadena total?. Una posible definición del caso general de la recursión es esta: Calculo la longitud de la lista sin el primer elemento con una llamada a la recursión, y le sumo 1 al número que devuelve esa llamada. Lo podríamos representar de la siguiente forma: Longitud (lista) = 1 + Longitud (resto (lista)) Y, por último, necesitamos que la función devuelva un valor concreto cuando llegue al caso base de la recursión. El caso base puede ser la lista vacía, que tiene una longitud de 0: Longitud (lista-vacía) = 0 La implementación en Scheme es: (define (mi-length items) (if (null? items) 0 (+ 1 (length (cdr items))))) Lista palíndroma Veamos un ejemplo algo más complicado cómo definimos una lista palíndroma de forma recursiva?. Por ejemplo, las siguientes listas son palíndromas:

4 '( ) '(1 2 1) '(1) '() Comenzamos con una definición no recursiva: Una lista es palíndroma cuando es igual a su inversa. Esta definición no es recursiva porque no llamamos a la recursión con un caso más sencillo. La definición recursiva del caso general es la siguiente: Una lista es palíndroma cuando su primer elemento es igual que el último y la lista resultante de quitar el primer y el último elemento también es palíndroma En el caso base debemos buscar el caso más pequeño no contemplado por la definición anterior. En este caso, una lista de un elemento y una lista vacía también las consideraremos palíndromas. palindroma(lista) <=> (primer-elemento(lista) == ultimo-elemento(lista)) y palindroma(quitar-primero-ultimo(lista)) palindroma(lista) <=> un-elemento(lista) o vacía(lista) Vamos a escribirlo en Scheme: (define (palindromo? lista) (or (null? lista) (null? (cdr lista)) (and (equal? (car lista) (ultimo lista)) (palindromo? (quitar-primero-ultimo lista))))) La función auxiliar quitar-primero-ultimo la podemos definir así: (define (quitar-ultimo lista) (if (null? (cdr lista)) '() (cons (car lista) (quitar-ultimo (cdr lista))))) (define (quitar-primero-ultimo lista) (cdr (quitar-ultimo lista)))

5 Triángulo de Sierpinski Triángulo de Sierpinski Ves alguna recursión en la figura? Cuál podría ser el parámetro de la función que la dibujara? Se te ocurre un algoritmo recursivo que la dibuje? La figura es autosimilar (una característica de las figuras fractales). Una parte de la figura es idéntica a la figura total, pero reducida de escala. Esto nos da una pista de que es posible dibujar la figura con un algoritmo recursivo. Para intentar encontrar una forma de enfocar el problema, vamos a pensarlo de la siguiente forma: supongamos que tenemos un triángulo de Sierpinski de anchura h y altura h/2 con su esquina inferior izquierda en la posición 0,0. Cómo podríamos construir el siguiente triángulo de Sierpinski?. Podríamos construir un triángulo de Sierpinski más grande dibujando 3 veces el mismo triángulo, pero en distintas posiciones: 1. Triángulo 1 en la posición (0,0) 2. Triángulo 2 en la posición (h/2,h/2) 3. Triángulo 3 en la posición (h,0) El algoritmo recursivo se basa en la misma idea, pero hacia atrás. Debemos intentar dibujar un triángulo de altura h situado en la posición x, y basándonos en 3 llamadas recursivas a triángulos más pequeños. En el caso base, cuando h sea menor que un umbral, dibujaremos un triángulo de lado h y altura h/2: O sea, que para dibujar un triángulo de Sierpinski de base h y altura h/2 debemos: Dibujar tres triángulos de Sierpinsky de la mitad del tamaño del original (h/2) situadas en

6 las posiciones (x,y), (x+h/4, y+h/4) y (x+h/2,y) En el caso base de la recursión, en el que h es menor que una constante, se dibuja un triángulo de base h y altura h/2. Una versión del algoritmo en pseudocódigo: Sierpinsky (x, y, h): if (h > MIN) { Sierpinsky (x, y, h/2) Sierpinsky (x+h/4, y+h/4, h/2) Sierpinsky (x+h/2, y, h/2) } else dibujatriangulo (x, y, h) Gráficos de tortuga en Racket Se pueden utilizar los gráficos de tortuga en Racket cargando la librería graphics/turtles : (require graphics/turtles) estando en el lenguaje Muy Grande. (require graphics/turtles) (turtles #t) Los comandos más importantes: (turtles #t) : abre una ventana y coloca la tortuga en el centro, mirando hacia el eje X (derecha) (clear) : borra la ventana y coloca la tortuga en el centro (draw d) : avanza la tortuga dibujando d píxeles (move d) : mueve la tortuga d píxeles hacia adelante (sin dibujar) (turn g) : gira la tortuga g grados (positivos: en el sentido contrario a las agujas del reloj) Prueba a realizar algunas figuras con los comandos de tortuga, antes de escribir el algoritmo en Scheme del triángulo de Sierpinski. Por ejemplo, podemos definir una función que dibuja un triángulo rectángulo con catetos de longitud x :

7 (define (hipot x) (* x (sqrt 2))) (define (triangulo x) (draw x) (turn 90) (draw x) (turn 135) (draw (hipot x)) (turn 135)) (triangulo 100) La función (hipot x) devuelve la longitud de la hipotenusa de un triángulo rectángulo con dos lados de longitud x. O sea, la expresión: hipot(x) = x 2 + x 2 = x 2 Como puedes comprobar, el código es imperativo. Se basa en realizar una serie de pasos de ejecución que modifican el estado (posición y orientación) de la tortuga. Es posible usar gráficos de tortuga de forma recursiva? Una forma de hacerlo sería usar programación funcional para generar una lista de comandos y usar código imperativo sólo en la función que realiza el dibujo de la lista de comandos. Por ejemplo, la lista de comandos que dibuja un triángulo rectángulo con lados 100 sería: '((draw l00) (turn 90) (draw l00) (turn 135) (draw (hipot 100)) (turn 135)) Podemos ejecutar esta lista de comandos con un enfoque imperativo. Para ello, definimos la siguiente función run que recibe una lista de comandos como la anterior y los ejecuta, mediante una llamada a eval para que evalúe el primer comando de la lista y una llamada recursiva que ejecuta el resto:

8 (define (run comandos) (if (not (null? comandos)) (begin (eval (car comandos)) (run (cdr comandos))))) Por ejemplo, el siguiente código dibuja un triángulo rectángulo con los dos catetos de longitud 100: (draw 100) (turn 90) (draw 100) (turn 135) (draw (hipot 100)) Podemos definir la función triangulo-list x que devuelve una lista de comandos: (define (triangulo-list x) (list (list 'draw x) '(turn 90) (list 'draw x) '(turn 135) (cons 'draw (list (list 'hipot x))) '(turn 135))) Y llamar a run con lo que devuelve la llamada anterior: (run (triangulo-list 100)) Sierpinski en Racket La siguiente es una versión imperativa del algoritmo que dibuja el triángulo de Sierpinski. No es funcional porque se realizan pasos de ejecución, usando la forma especial begin o múltiples instrucciones en una misma función (por ejemplo la función triangle ).

9 (require graphics/turtles) (turtles #t) (define (hipot x) (* x (sqrt 2))) (Define (triangle w) (draw w) (turn 135) (draw (hipot (/ w 2))) (turn 90) (draw (hipot (/ w 2))) (turn 135)) (define (sierpinski w) (if (> w 20) (begin (sierpinski (/ w 2)) (move (/ w 4)) (turn 90) (move (/ w 4)) (turn -90) (sierpinski (/ w 2)) (turn -90) (move (/ w 4)) (turn 90) (move (/ w 4)) (sierpinski (/ w 2)) (turn 180) (move (/ w 2)) (turn -180)) ;; volvemos a la posició n original (triangle w))) Sierpinski funcional Usando la misma idea que vimos anteriormente, podemos construir la función equivalente a sierpinski pero que en lugar de dibujar, devuelve una lista de comandos. La llamamos sierpinski-list :

10 (define (triangle-list w) (list (list 'draw w) '(turn 135) (list 'draw (hipot (/ w 2))) '(turn 90) (list 'draw (hipot (/ w 2))) '(turn 135))) (define (sierpinski-list w) (if (> w 20) (append (sierpinski-list (/ w 2)) (list (list 'move (/ w 4)) '(turn 90) (list 'move (/ w 4)) '(tu rn -90)) (sierpinski-list (/ w 2)) (list '(turn -90) (list 'move (/ w 4)) '(turn 90) (list 'move ( / w 4))) (sierpinski-list (/ w 2)) (list '(turn 180) (list 'move (/ w 2)) '(turn -180))) ;; volvem os a la posición original (triangle-list w))) Por ejemplo, (sierpinski-list 40) devuelve la siguiente lista de comandos: ((draw 20) (turn 135) (draw ) (turn 90) (draw ) (turn 135) (move 10) (turn 90) (move 10) (turn -90) (draw 20) (turn 135) (draw ) (turn 90) (draw ) (turn 135) (turn -90) (move 10) (turn 90) (move 10) (draw 20) (turn 135) (draw ) (turn 90) (draw ) (turn 135) (turn 180) (move 20) (turn -180)) Que se dibujan con una llamada a la función run produciendo la siguiente figura: Sierpinski Recursión mutua

11 En la recursión mutua definimos una función en base a una segunda, que a su vez se define en base a la primera. También debe haber un caso base que termine la recursión Por ejemplo: x es par si x 1 es impar x es impar si x 1 es par 0 es par Programas en Scheme: (define (par? x) (if (= 0 x) #t (impar? (- x 1)))) (define (impar? x) (if (= 0 x) #f (par? (- x 1)))) Ejemplo avanzado: curvas de Hilbert La curva de Hilbert es una curva fractal que tiene la propiedad de rellenar completamente el espacio Su dibujo tiene una formulación recursiva Curva de Hilbert La curva H3 se puede construir a partir de la curva H2. El algoritmo recursivo se formula dibujando la curva i-ésima a partir de la curva i 1. Como en la curva de Sierpinsky, utilizamos la librería graphics/turtles, que permite usar la tortuga de Logo con los comandos de Logo draw y turn

12 La función (h-der i w) dibuja una curva de Hilbert de orden i con una longitud de trazo w a la derecha de la tortuga La función (h-izq i w) dibuja una curva de Hilbert de orden i con una longitud de trazo w a la izquierda de la tortuga Para dibujar una curva de Hilbert de orden i a la derecha de la tortuga: 1. Gira la tortuga Dibuja una curva de orden i-1 a la izquierda 3. Avanza w dibujando 4. Gira Dibuja una curva de orden i-1 a la derecha 6. Avanza w dibujando 7. Dibuja una curva de orden i-1 a la derecha 8. Gira Avanza w dibujando 10. Dibuja una curva de orden i-1 a la izquierda 11. Gira -90 El algoritmo para dibujar a la izquierda es simétrico El algoritmo en Scheme:

13 (require graphics/turtles) (turtles #t) (define (h-der i w) (if (> i 0) (begin (turn -90) (h-izq (- i 1) w) (draw w) (turn 90) (h-der (- i 1) w) (draw w) (h-der (- i 1) w) (turn 90) (draw w) (h-izq (- i 1) w) (turn -90)))) (define (h-izq i w) (if (> i 0) (begin (turn 90) (h-der (- i 1) w) (draw w) (turn -90) (h-izq (- i 1) w) (draw w) (h-izq (- i 1) w) (turn -90) (draw w) (h-der (- i 1) w) (turn 90)))) Podemos probarlo con distintos parámetros de grado de curva y longitud de trazo: (clear) (h-izq 3 20) (h-izq 6 5) El resultado de esta última llamada es:

14 Hilbert en Scheme 1.2. El coste de la recursión La pila de la recursión Vamos a estudiar el comportamiento del proceso generado por una llamada a un procedimiento recursivo. Supongamos la función mi-length : (define (mi-length items) (if (null? items) 0 (+ 1 (mi-length (cdr items))))) Examinamos cómo se evalúan las llamadas recursivas: (mi-length '(a b c d)) (+ 1 (mi-length '(b c d))) (+ 1 (+ 1 (mi-length '(c d)))) (+ 1 (+ 1 (+ 1 (mi-length '(d))))) (+ 1 (+ 1 (+ 1 (+ 1 (mi-length '()))))) (+ 1 (+ 1 (+ 1 (+ 1 0)))) (+ 1 (+ 1 (+ 1 1))) (+ 1 (+ 1 2)) (+ 1 3) 4

15 Cada llamada a la recursión deja una función en espera de ser evaluada cuando la recursión devuelva un valor (en el caso anterior el +). Esta función, junto con sus argumentos, se almacenan en la pila de la recursión. Cuando la recursión devuelve un valor, los valores se recuperan de la pila, se realiza la llamada y se devuelve el valor a la anterior llamada en espera. Si la recursión está mal hecha y nunca termina se genera un stack overflow. Es posible hacer que Racket haga una traza de la secuencia de llamadas a la recursión utilizando la librería trace.ss. Una vez cargada la librería puedes activar y desactivar las trazas de funciones específicas con (trace <función>) y (untrace <función>). Debes tener activo el lenguaje Muy Grande. Un pequeño problema de las trazas es que sólo se pueden tracear funciones definidas por el usuario, no se pueden tracear funciones primitivas de Scheme como + o car. Si queremos comprobar un ejemplo de traza en donde haya una llamada a una función primitiva, podemos definir una función propia que llame a la primitiva y tracear nuestra función. Por ejemplo, vamos a tracear las llamadas recursivas a mi-length y a la suma:

16 (require (lib "trace.sss)) (define (suma x y) (+ x y)) (define (mi-length lista) (if (null? lista) 0 (suma 1 (mi-length (cdr lista))))) (trace suma) (trace mi-length) (mi-length '(a b c d e f)) >(mi-length '(a b c d e f)) > (mi-length '(b c d e f)) > >(mi-length '(c d e f)) > > (mi-length '(d e f)) > > >(mi-length '(e f)) > > > (mi-length '(f)) > > > >(mi-length '()) < < < <0 > > > (suma 1 0) < < < 1 > > >(suma 1 1) < < <2 > > (suma 1 2) < < 3 > >(suma 1 3) < <4 > (suma 1 4) < 5 >(suma 1 5) < Coste espacial de la recursión El coste espacial de un programa es una función que relaciona la memoria consumida por una llamada para resolver un problema con alguna variable que determina el tamaño del problema a resolver. En el caso de la función mi-length el tamaño del problema viene dado por la longitud de la lista. El coste espacial de mi-lenght es O(n), siendo n la longitud de la lista El coste depende del número de llamadas a la recursión

17 Veamos con un ejemplo que el coste de las llamadas recursivas puede dispararse. Supongamos la famosa secuencia de Fibonacci: 0,1,1,2,3,5,8,13, Formulación matemática de la secuencia de Fibonacci: >Fibonacci(n) = Fibonacci(n-1) + Fibonacci(n-2) >Fibonacci(0) = 0 >Fibonacci(1) = 1 Formulación recursiva en Scheme: (define (fib n) (cond ((= n 0) 0) ((= n 1) 1) (else (+ (fib (- n 1)) (fib (- n 2)))))) Evaluación de una llamada a Fibonacci: Llamada recursiva a Fibonacci Cada llamada a la recursión produce otras dos llamadas, por lo que el número de llamadas finales es 2 n siendo n el número que se pasa a la función. El coste espacial y temporal es exponencial, O(2 n ). Qué pasa si intentamos evaluar (fibonaci 100)?

18 1.3. Soluciones al coste de la recursión: procesos iterativos Diferenciamos entre procedimientos y procesos: un procedimiento es un algoritmo y un proceso es la ejecución de ese algoritmo. Es posible definir procedimientos recursivos que generen procesos iterativos (como los bucles en programación imperativa) en los que no se dejen llamadas recursivas en espera ni se incremente la pila de la recursión. Para ello construimos la recursión de forma que en cada llamada se haga un cálculo parcial y en el caso base se pueda devolver directamente el resultado obtenido. Este estilo de recursión se denomina recursión por la cola (tail recursion, en inglés). Se puede realizar una implementación eficiente de la ejecución del proceso, eliminando la pila de la recursión Factorial iterativo Es posible modificar la formulación de la recursión para se eviten las llamadas en espera: Definimos la función (fact-iter-aux product n) que es la que define el proceso iterativo Tiene un parámetro adicional ( product ) que es el parámetro en el que se irán guardando los cálculos intermedios Al final de la recursión el factorial debe estar calculado en product y se devuelve (define (factorial-iter n) (fact-iter-aux n n)) (define (fact-iter-aux product n) (if (= n 1) product (fact-iter-aux (* product (- n 1)) (- n 1)))) Secuencia de llamadas:

19 (factorial-iter 4) (factorial-iter-aux 4 4) (factorial-iter-aux 12 3) (factorial-iter-aux 24 2) (factorial-iter-aux 24 1) Versión iterativa de mi-length Cómo sería la versión iterativa de mi-length? Solución: (define (mi-length-iter lista) (mi-length-iter-aux lista 0)) (define (mi-length-iter-aux lista result) (if (null? lista) result (mi-length-iter-aux (cdr lista) (+ result 1)))) Procesos iterativos La recursión resultante es menos elegante Se necesita una parámetro adicional en el que se van acumulando los resultados parciales La última llamada a la recursión devuelve el valor acumulado El proceso resultante de la recursión es iterativo en el sentido de que no deja llamadas en espera ni incurre en coste espacial Fibonacci iterativo Cualquier programa recursivo se puede transformar en otro que genera un proceso iterativo. En general, las versiones iterativas son menos intuitivas y más difíciles de entender y depurar. Ejemplo: Fibonacci iterativo

20 (define (fib-iter n) (fib-iter-aux 1 0 n)) (define (fib-iter-aux a b count) (if (= count 0) b (fib-iter-aux (+ a b) a (- count 1)))) Triángulo de Pascal Formulación matemática: Pascal (0,0) = Pascal (1,0) = Pascal (1,1) = 1 Pascal (fila, columna) = Pascal (fila 1,columna 1) + Pascal (fila 1, columna) La versión recursiva pura: (define (pascal row col) (cond ((= col 0) 1) ((= col row) 1) (else (+ (pascal (- row 1) (- col 1)) (pascal (- row 1) col) )))) La versión iterativa:

21 (define (pascal-iter fila col) (list-ref (pascal-iter-aux '(1 1) fila) col)) (define (pascal-iter-aux fila n) (if (= n (length fila)) fila (pascal-iter-aux (pascal-sig-fila fila) n))) (define (pascal-sig-fila fila) (append '(1) (pascal-sig-fila-central fila) '(1))) (define (pascal-sig-fila-central fila) (if (= 1 (length fila)) '() (append (list (+ (car fila) (car (cdr fila)))) (pascal-sig-fila-central (cdr fila))))) 1.4. Soluciones al coste de la recursión: memoization Una alternativa que mantiene la elegancia de los procesos recursivos y la eficiencia de los iterativos es la memoization. Si miramos la traza de (fibonacci 4) podemos ver que el coste está producido por la repetición de llamadas; por ejemplo (fibonacci 3) se evalúa 2 veces. En programación funcional la llamada a (fibonacci 3) siempre va a devolver el mismo valor. Podemos guardar el valor devuelto por la primera llamada en alguna estructura (una lista de asociación, por ejemplo) y no volver a realizar la llamada a la recursión las siguientes veces Fibonacci con memoization Usamos los métodos procedurales put y get que implementan un diccionario clave-valor (para probarlos hay que utilizar el lenguaje R5RS):

22 (define lista (list '*table*)) (define (get key lista) (let ((record (assq key (cdr lista)))) (if (not record) '() (cdr record)))) (define (put key value lista) (let ((record (assq key (cdr lista)))) (if (not record) (set-cdr! lista (cons (cons key value) (cdr lista))) (set-cdr! record value))) 'ok) La función (put key value lista) asocia un valor a una clave y la guarda en la lista (con mutación). La función (get key lista) devuelve el valor de la lista asociado a una clave. Ejemplos: (define mi-lista (list '*table*)) (put 1 10 mi-lista) (get 1 mi-lista) -> 10 (get 2 mi-lista) -> '() La función fib-memo realiza el cálculo de la serie de Fibonacci utilizando el proceso recursivo visto anteriormente y la técnica de memoización, en la que se consulta el valor de Fibonacci de la lista antes de realizar la llamada recursiva: (define (fib-memo n lista) (cond ((= n 0) 0) ((= n 1) 1) ((not (null? (get n lista))) (get n lista)) (else (let ((result (+ (fib-memo (- n 1) lista) (fib-memo (- n 2) lista)))) (begin (put n result lista) result)))))

23 Podemos comprobar la diferencia de tiempos de ejecución entre esta versión y la anterior. El coste de la función memoizada es O(n). Frente al coste O(2 n ) de la versión inicial que la hacía imposible de utilizar. (define lista (list '*table*)) (fib-memo 200 lista) -> Listas estructuradas Hemos visto temas anteriores que las listas en Scheme se implementan como un estructura de datos recursiva, formadas a partir de parejas y de una lista vacía. Una vez conocida su implementación, vamos a volver a estudiar las listas desde un nivel de abstracción alto, usando las funciones car y cdr para obtener el primer elemento y el resto de la lista y la función cons para añadir un nuevo elemento a su cabeza. En la mayoría de funciones y ejemplos que hemos visto hasta ahora las listas están formadas por datos y el recorrido por la lista es un recorrido lineal, una iteración por sus elementos. En este apartado vamos a ampliar este concepto y estudiar cómo trabajar con listas que contienen otras listas Definición y ejemplos Las listas en Scheme pueden tener cualquier tipo de elementos, incluido otras listas. Llamaremos lista estructurada a una lista que contiene otras sublistas. Lo contrario de lista estructurada es una lista plana, una lista formada por elementos que no son listas. Llamaremos hojas a los elementos de una lista que no son sublistas. Por ejemplo, la lista estructurada: '(a b (c d e) (f (g h))) es una lista estructurada con 4 elementos: El elemento 'a, una hoja El elemento 'b, otra hoja La lista plana '(c d e) La lista estructurada '(f (g h)) Una lista formada por parejas la consideraremos una lista plana, ya que no contiene ninguna sublista. Por ejemplo, la lista

24 ((a. 3) (b. 5) (c. 12)) es una lista plana de tres elementos (hojas) que son parejas Definiciones en Scheme Vamos a escribir las definiciones anteriores en código de Scheme. Un dato es una hoja si no es una lista: (define (hoja? dato) (not (list? dato))) Una definición recursiva de lista plana: Una lista es plana si y solo si el primer elemento es una hoja y el resto es plana. Y el caso base: Una lista vacía es plana. En Scheme: (define (plana? lista) (or (null? lista) (and (hoja? (car lista)) (plana? (cdr lista))))) Una lista es estructurada cuando alguno de sus elementos es otra lista: (define (estructurada? lista) (if (null? lista) #f (or (list? (car lista)) (estructurada? (cdr lista))))) Ejemplos:

25 (plana? '(a b c d e f)) #t (plana? '((a. 1) (b. 2) (c. 3))) #t (plana? '(a (b c) d)) #f (plana? '(a () b)) #f (estructurada? '( )) #f (estructurada? '((a. 1) (b. 2) (c. 3))) #f (estructurada? '(a () b)) #t (estructurada? '(a (b c) d)) #t Realmente bastaría con haber hecho una de las dos definiciones y escribir la otra como la negación de la primera: (define (estructurada? lista) (not (plana? lista))) O bien: (define (plana? lista) (not (estructurada? lista))) Ejemplos de listas estructuradas Las listas estructuradas son muy útiles para representar información jerárquica en donde queremos representar elementos que contienen otros elementos. Por ejemplo, las expresiones de Scheme son listas estructuradas: '(= 4 (+ 2 2)) '(if (= x y) (* x y) (+ (/ x y) 45)) '(define (factorial x) (if (= x 0) 1 (* x (factorial (- x 1))))) El análisis sintáctico de una oración puede generar una lista estructurada de símbolos, en donde se agrupan los distintos elementos de la oración: '((Juan) (compró) (la entrada (de los Miserables)) (el viernes por la tar de)) Una página HTML, con sus distintos elementos, unos dentro de otros, también se puede representar con una lista estructurada:

26 '((<h1> Mi lista de la compra </h1>) (<ul> (<li> naranjas </li>) (<li> tomates </li>) (<li> huevos </li>) </ul>)) 2.2. Pseudo árboles con niveles Las listas estructuradas definen una estructura de niveles, donde la lista inicial representa el primer nivel, y cada sublista representa un nivel inferior. Los datos de las listas representan las hojas. Por ejemplo, la representación en forma de niveles de la lista '((1 2 3) 4 5) es la siguiente: La estructura no es un árbol propiamente dicho, porque todos los datos están en las hojas. Otro ejemplo. Cuál sería la representación en niveles de la siguiente lista estructurada?: '(let ((x 12) (y 5)) (+ x y))) Altura de una lista estructurada La altura de una lista estructurada viene dada por su número de niveles: una lista plana tiene una altura de 1, la lista anterior tiene una altura de 2. Veamos una definición más precisa. altura(lista vacía) = 0 altura(hoja) = 0 altura(lista) = max (1 + altura (primer-elemento (lista)), altura (resto (lista)) En Scheme:

27 (define (altura lista) (cond ((null? lista) 0) ((hoja? lista) 0) (else (max (+ 1 (altura (car lista))) (altura (cdr lista)))))) Por ejemplo: (altura '(1 (2 3) 4)) 2 (altura '(1 (2 (3)) 3)) 3 Hay que hacer notar que en la función anterior que el parámetro lista va a aceptar tanto hojas como listas Implementación de altura con map Es posible definir la función utilizando las función de orden superior map para aplicar la propia función que estamos definiendo a los elementos de la lista: (define (altura lista) (cond ((null? lista) 0) ((hoja? lista) 0) (else (+ 1 (apply max (map altura lista)))))) 2.3. Funciones recursivas sobre listas estructuradas Vamos a diseñar distintas funciones recursivas que trabajan con la estructura jerárquica de las listas estructuradas. (num-hojas lista) : cuenta las hojas de una lista estructurada (pertenece? lista) : busca una hoja en una lista estructurada (cuadrado-lista lista) : eleva todas las hojas al cuadrado (suponemos que la lista estructurada contiene números) (map-lista f lista) : similar a map, aplica una función a todas las hojas de la lista estructurada y devuelve el resultado (otra lista estructurada) num-hojas Cuenta el número de hojas de una lista estructurada.

28 Definición matemática: num-hojas(lista vacía) = 0 num-hojas(hoja) = 1 num-hojas(lista) = num-hojas (primer-elemento (lista)) + num-hojas (resto (lista)) Implementación en Scheme: (define (num-hojas lista) (cond ((null? lista) 0) ((hoja? lista) 1) (else (+ (num-hojas (car lista)) (num-hojas (cdr lista)))))) Por ejemplo: (num-hojas '(1 2 (3 4 (5) 6) (7))) 7 Con map y apply : (define (num-hojas lista) (cond ((null? lista) 0) ((hoja? lista) 1) (else (apply + (map num-hojas lista))))) pertenece? Comprueba si el dato x aparece en la lista estructurada. (define (pertenece? x lista) (cond ((null? lista) #f) ((hoja? lista) (equal? x lista)) (else (or (pertenece? x (car lista)) (pertenece? x (cdr lista)))))) Ejemplos: (pertenece? 'a '(b c (d (a)))) #t (pertenece? 'a '(b c (d e (f)) g)) #f

29 cuadrado-lista Devuelve una lista estructurada con la misma estructura y sus números elevados al cuadrado. (define (cuadrado-lista lista) (cond ((null? lista) '()) ((hoja? lista) (* lista lista)) (else (cons (cuadrado-lista (car lista)) (cuadrado-lista (cdr lista)))))) Por ejemplo: (cuadrado-lista '(2 3 (4 (5)))) (4 9 (16 (25)) map-lista Devuelve una lista estructurada igual que la original con el resultado de aplicar a cada uno de sus hojas la función f (define (map-lista f lista) (cond ((null? lista) '()) ((hoja? lista) (f lista)) (else (cons (map-lista f (car lista)) (map-lista f (cdr lista)))))) Por ejemplo: (map-lista (lambda (x) (* x x)) '(2 3 (4 (5)))) (4 9 (16 (25)) 2.4. Ejercicios Planteamos a continuación algunos ejercicios para que practiquéis las funciones recursivas sobre las listas estructuradas. tres-elementos? Escribe la función (tres-elementos? lista) que tome una lista estructurada como argumento. Devolverá #t si cada subsista que aparece y cada uno de sus elementos tienen 3 elementos. Suponemos que nunca se llamará a la función con una lista vacía. Ejemplos:

30 (tres-elementos? '(1 2 3)) #t (tres-elementos? '((1 2 3) 2 3)) #t (tres-elementos? '((1 2 3) (4 5 6))) #f (tres-elementos? '(1 2 (3 3))) #f diff-listas Escribe la función (diff-listas l1 l2) que tome como argumentos dos listas estructuradas con la misma estructura, pero con diferentes elementos, y devuelva una lista de parejas que contenga los elementos que son diferentes. Ejemplos: (dif-listas '(a (b ((c)) d e) f) '(1 (b ((2)) 3 4) f)) ((a. 1) (c. 2) (d. 3) (e. 4)) (diff-listas '() '()) () (diff-listas '((a b) c) '((a b) c)) () transformar Define un procedimiento llamado (transformar plantilla lista) que reciba dos listas como argumento: la lista plantilla será una lista estructurada y estará compuesta por números enteros positivos con una estructura jerárquica, como (2 (3 1) 0 (4)). La segunda lista será una lista plana con tantos elementos como indica el mayor número de plantilla más uno (en el caso anterior serían 5 elementos). El procedimiento deberá devolver una lista estructurada donde los elementos de la segunda lista se sitúen (en situación y en estructura) según indique la plantilla. Ejemplos: (transformar '((0 1) 4 (2 3)) '(hola que tal estas hoy)) ((hola que) hoy (tal estas)) (transformar '( (0)) '(vamos todos a aprobar este examen)) (todos este aprobar a examen (vamos)) nivel-hoja Escribe la función (nivel-hoja dato lista) que recorra la lista buscando el dato y devuelva el nivel en que se encuentra. Suponemos que el dato está en la lista y no está repetido.

31 Ejemplos: (nivel-hoja 2 '(1 2 (3))) 1 (nivel-hoja 2 '(1 (2) 3)) 2 (nivel-hoja 2 '(1 3 4 ((2))) 4 hojas-nivel Define la función (hojas-nivel lista) que reciba una lista estructurada y devuelva una lista de parejas con las hojas y la profundidad en que se encuentra cada hoja. Ejemplos: (hojas-nivel '(2 3 4 (5) ((6)))) ((2.1) (3.1) (4.1) (5.2) (6.3)) (hojas-nivel '(2 (5 (8 9) 10 1))) ((2.1) (5.2) (8.3) (9.3) (10.2) (1.2)) acumula Define la función (acumula lista nivel) que reciba una lista estructurada compuesta por números y un número de nivel. Devolverá la suma de todos los nodos hoja que tengan una profundidad mayor o igual que el nivel indicado. Ejemplos: (acumula '(2 3 4 (5) ((6))) 2) 11 (acumula '(2 3 4 (5) ((6))) 3) 6 (acumula '(2 (5 (8 9) 10 1)) 3) Datos funcionales y barreras de abstracción 3.1. Datos funcionales Hablamos de datos funcionales para referirnos a valores inmutables de primera clase (que podemos asignar a variables). Ejemplos en Scheme: int, boolean, char, string, pareja, Un dato funcional se inicializa con un estado, pero no se puede modificar una vez creado. Sí que podemos construir nuevos datos a partir de datos ya existentes. Pero la característica fundamental es su inmutabilidad. En las operaciones en las que intervienen datos funcionales siempre se devuelve un dato

32 nuevo recién creado; los objetos matemáticos son así. Por ejemplo, si sumamos dos números racionales el resultado es un número nuevo; los números que intervienen en la operación no se modifican. Los datos funcionales son muy útiles y se recomienda su utilización en la mayoría de lenguajes. En los lenguajes orientados a objetos como Java o Scala este tipo de datos reciben el nombre de objetos valor - ver p. 73 Effective Java Programming, Joshua Bloch). Los lenguajes de programación funcional no proporcionan mecanismos como los de clases o interfaces para definir nuevos datos. Debemos crearlos de forma ad-hoc definiendo un conjunto de funciones que construyen y trabajan con los datos y teniendo la disciplina de sólo utilizar esas para operar con los datos. Es lo que llamamos barrera de abstracción del dato. Al definir nuevas operaciones que trabajen con un dato no debemos saltar esa barrera de abstracción Abstracción de datos Cita de Abelson y Sussman en la que explica el concepto de abstracción de datos: When defining procedural abstraction we make an abstraction that separates the way the procedure would be used from the details of how the procedure is implemented in terms of more primitive procedures. The analogous notion for compound data is called data abstraction. Data abstraction is a methodology that enables us to isolate how a compound data object is used from the details of how it is constructed from more primitive data objects. The basic idea of data abstraction is to structure the programs that are to use compound data objects so that they operate on abstract data. That is, our programs should use data in such a way as to make no assumptions about the data that are not strictly necessary for performing the task at hand. At the same time, a concrete data representation is defined independent of the programs that use the data. The interface between these two parts of our system will be a set of procedures, called selectors and constructors, that implement the abstract data in terms of the concrete representation Barrera de abstracción Definimos como barrera de abstracción (o interfaz) de un dato funcional al conjunto de funciones que nos permiten trabajar con él y que separan su uso de su implementación.

33 ;; ;; ;; ;; ;; USO DE LA ABSTRACCION ;; ;; ;; ;; INTERFAZ: funciones ;; ;; ;; ;; IMPLEMENTACION ;; ;; ;; ;; ;; La funciones que están por encima de la barrera de abstracción deben usar las funciones propuestas por la barrera. De esta forma se esconde la implementación y se independiza las funciones que usan la abstracción de su implementación Ejemplo de barrera de abstracción para construir datos: números racionales Veamos un ejemplo de dato funcional. Supongamos que queremos construir el tipo de dato número racional, un número formado por un numerador y un denominador, con las operaciones típicas de suma, resta, multiplicación y división. Vamos a definir una nomenclatura estándar para nombrar a las funciones de la barrera de abstracción. Utilizaremos el sufijo rat (del inglés rational ) para todas las funciones que trabajan con el nuevo tipo de datos. La barrera de abstracción está formada por constructores, selectores y operadores: Constructores: Funciones que devuelven un nuevo dato creado a partir de sus elementos Selectores: Funciones que devuelven algún elemento a partir del dato Operadores: Funciones que definen operaciones sobre los datos. Algunas devuelven nuevos datos resultantes de la operación o devuelven otros tipos En programación funcional no existen mutadores. Una vez construido un dato no se puede modificar (eso sí, se puede construir un nuevo dato a partir de los ya existentes) Diseño de la barrera de abstracción números racionales En el caso de los números racionales, vamos a definir las siguientes funciones: Constructor (o constructores): make-rac Selectores y operadores: num-rac, denom-rac, suma-rac, sub-rac,

34 div-rac Constructores (make-rac num denom) : Toma dos números enteros num y denom y devuelve un nuevo número racional cuyo numerador es num y denominador es denom. Selectores (num-rac rac) : Toma un número racional y devuelve su numerador. (denom-rac rac) : Toma un número racional y devuelve su denominador. Operadores (suma-rac r1 r2) : Toma dos números racionales r1 y r2 y devuelve su suma. (resta-rac r1 r2) : Toma dos números racionales r1 y r2 y devuelve su resta. (mult-rac r1 r2) : Toma dos números racionales r1 y r2 y devuelve su multiplicación. (div-rac r1 r2) : Toma dos números racionales r1 y r2 y devuelve su división Implementación de los datos racionales

35 (define (make-rac numer denom) (cons numer denom)) (define (num-rac rac) (car rac)) (define (denom-rac rac) (cdr rac)) (define (add-rac x y) (make-rac (+ (* (num-rac x) (denom-rac y)) (* (num-rac y) (denom-rac x))) (* (denom-rac x) (denom-rac y)))) (define (sub-rac x y) (make-rac (- (* (num-rac x) (denom-rac y)) (* (num-rac y) (denom-rac x))) (* (denom-rac x) (denom-rac y)))) (define (mul-rac x y) (make-rac (* (num-rac x) (num-rac y)) (* (denom-rac x) (denom-rac y)))) (define (div-rac x y) (make-rac (* (num-rac x) (denom-rac y)) (* (denom-rac x) (num-rac y)))) (define (equal-rac? x y) (= (* (num-rac x) (denom-rac y)) (* (denom-rac x) (num-rac y)))) (define (rac->string rac) (string-append (number->string (num-rac rac)) "/" (number->string (denom-rac rac)))) Una vez definida la barrera de abstracción, hemos creado una nueva abstracción que amplía el vocabulario y las capacidades de nuestros programas. Ahora podemos usar números racionales de la misma forma que usamos números enteros o reales:

36 (define r1 (make-rac 1 3)) ; r1 = 1/3 (num-rac r1) 1 (denom-rac r1) 3 (define r2 (make-rac 2 3)) (define r3 (add-rac r1 r2)) (rac->string r2) "2/3" (rac->string r3) "9/9" 3.3. Modificación de la implementación Una de las ventajas de definir una barrera de abstracción es que es posible cambiar la implementación de las funciones sin afectar a las funciones que las usan. Si esas funciones han respetado la definición de la barrera y no han accedido directamente a la implementación van a seguir funcionando sin problemas. Veamos un ejemplo. Vamos a modificar la implementación del número racional para añadir a la estructura el símbolo racional. Este símbolo nos va a permitir añadir un predicado que compruebe si un dato es del tipo racional. Tenemos que modificar el constructor make-racional y los selectores num-rac y denom-rac : (define (make-rac numer denom) (cons 'racional (cons numer denom))) (define (num-rac rac) (cadr rac)) (define (denom-rac rac) (cddr rac)) El resto de funciones no hay que tocarlas, siguen funcionando correctamente, porque hacen uso de estas funciones de la barrera de abstracción. Ahora ya podemos definir el predicado racional? que comprueba si un número es racional: (define (racional? x) (and (pair? x) (equal? (car x) 'racional))) Ejemplos:

37 (define r1 (make-rac 1 3)) ; r1 = 1/3 (racional? r1) #t (racional? 12) #f (num-rac r1) 1 (denom-rac r1) 3 (define r2 (make-rac 2 3)) (define r3 (suma-rac r1 r2)) (rac->string r2) "2/3" (rac->string r3) "9/9" 4. Árboles binarios 4.1. Barrera de abstracción de árbol binario Definición del árbol binario y de su barrera de abstracción Definición recursiva: Un árbol binario es una estructura que contiene un dato, un hijo izquierdo y un hijo derecho (ambos árboles binarios) Un árbol binario también puede ser un árbol vacío Un árbol binario En la asignatura no nos preocupa cuáles son los datos del árbol, ni su ordenación; sólo la estructura

38 Barrera de abstracción b-tree Funciones de la barrera: (make-bt dato izq-bt der-bt) : crea un árbol binario con un dato, un árbol binario izquierdo y un árbol binario derecho (make-hoja-bt dato) : crea una hoja, con su hijo izquierdo e hijo derecho vacíos 'vacio-bt : símbolo que define el árbol binario vacío (dato-bt bt) : devuelve el dato de un árbol binario (izq-bt bt) : devuelve el árbol binario izquierdo (der-bt bt) : devuelve el árbol binario derecho (hoja-bt? bt) : comprueba si el árbol es una hoja (no tiene hijos) (vacio-bt? bt) : comprueba si el árbol es vacío Implementación Implementación árbol binario Implementación de la estructura de datos: Un árbol binario es una lista con 3 elementos: el dato de la raíz, el árbol que forma el hijo

39 izquierdo y el árbol que forma el hijo derecho Implementación de las funciones: (define (make-bt dato izq der) (list dato izq der)) (define (make-hoja-bt dato) (make-bt dato 'vacio-bt 'vacio-bt)) (define (vacio-bt? btree) (equal? btree 'vacio-bt)) (define (dato-bt btree) (car btree)) (define (izq-bt btree) (car (cdr btree))) (define (der-bt btree) (car (cdr (cdr btree)))) (define (hoja-bt? btree) (and (vacio-bt? (izq-bt btree)) (vacio-bt? (der-bt btree)))) Por ejemplo, para construir el árbol binario de la figura anterior y operar con él: (define btree (make-bt 10 (make-bt 5 (make-hoja-bt 3) 'vacio-bt) (make-bt 23 (make-hoja-bt 12) (make-hoja-bt 28)))) (hoja-bt? (izq-bt btree)) #f (hoja-bt? (izq-bt (izq-bt btree))) #t (dato-bt (izq-bt (izq-bt btree))) 3 (dato-bt (izq-bt (der-bt btree))) 12 Con esta implementación, los árboles binarios son listas estructuradas de tres elementos. Por ejemplo, la lista estructurada del árbol anterior es: (10 (5 (3 vacio-bt vacio-bt) vacio-bt) (23 (12 vacio-bt vacio-bt) (28 vac io-bt vacio-bt))) 4.2. Funciones recursivas (to-list-bt bt) : devuelve una lista formada por los elementos del bt

40 (member-bt? x bt) : busca el elemento x en un árbol binario ordenado (insert-bt x bt) : inserta (realmente, no modifica el árbol que se pasa como parámetro, sino que crea otro) un dato en un árbol binario ordenado (insert-list-bt lista bt) : inserta una lista en un árbol binario ordenado (list-to-bt list) : construye un árbol binario ordenado a partir de una lista to-list-bt Devuelve una lista plana con todos los datos del árbol binario (define (to-list-bt btree) (if (vacio-bt? btree) '() (append (to-list-bt (izq-bt btree)) (list (dato-bt btree)) (to-list-bt (der-bt btree))))) Ejemplo: (to-list-bt btree) ( ) member-bt? Comprueba si un número pertenece a un árbol binario ordenado (define (member-bt? x bt) (cond ((vacio-bt? bt) #f) ((= x (dato-bt bt)) #t) ((< x (dato-bt bt)) (member-bt? x (izq-bt bt))) (else (member-bt? x (der-bt bt))))) Ejemplos: (member-bt? 12 btree) #t (member-bt? 13 btree) #f insert-bt Devuelve un nuevo árbol binario en el que se ha añadido un número (se aplica a árboles

41 binarios ordenados) (define (insert-bt x bt) (cond ((vacio-bt? bt) (make-hoja-bt x)) ((< x (dato-bt bt)) (make-bt (dato-bt bt) (insert-bt x (izq-bt bt)) (der-bt bt))) ((> x (dato-bt bt)) (make-bt (dato-bt bt) (izq-bt bt) (insert-bt x (der-bt bt)))) (else bt))) Ejemplos: (insert-bt 12 'vacio-bt) (12 vacio-bt vacio-bt) (define btree2 (insert-bt 13 btree)) (member-bt? 13 btree2) #t (hoja-bt? (izq-bt (der-bt btree2))) #f (dato-bt (der-bt (izq-bt (der-bt btree2)))) 13 btree2 (10 (5 (3 vacio-bt vacio-bt) vacio-bt) (23 (12 vacio-bt (13 vacio-bt vacio-bt)) (28 vacio-bt vacio-bt))) list-to-bt Devuelve un árbol binario ordenado resultado de añadir una lista de números a un árbol binario inicial (define (insert-list-bt list bt) (if (null? list) bt (insert-list-bt (cdr list) (insert-bt (car list) bt)))) Construye un árbol binario ordenado a partir de una lista de números

42 (define (list-to-bt lista) (insert-list-bt lista 'vacio-bt)) Ejemplo: (list-to-bt '( )) (12 (10 (1 vacio-bt vacio-bt) vacio-bt) (23 vacio-bt vacio-bt)) 5. Árboles genéricos 5.1. Barrera de abstracción Definición del árbol genérico y de su barrera de abstracción Una definición recursiva: Un árbol genérico está formado por un dato y una lista de árboles hijos (también árboles) La lista de árboles hijos puede ser vacía. No usamos el concepto de árbol-vacio, un árbol o nodo hoja es un árbol cuya lista de hijos es una lista vacía. Un ejemplo de árbol genérico Funciones: (make-tree dato lista-hijos) : construye un árbol a partir de un dato y una lista

43 de hijos formada por árboles. La lista puede ser vacía. (dato-tree tree) : devuelve el dato de la raíz del árbol (hijos-tree tree) : devuelve una lista de árboles hijos (hoja-tree? tree) : predicado que comprueba si el árbol es un nodo hoja (no tiene hijos) Bosque: lista de árboles (devueltos por la función hijos-tree) Implementación (define (make-tree dato lista-hijos) (cons dato lista-hijos)) (define (make-hoja-tree dato) (make-tree dato '())) (define (dato-tree tree) (car tree)) (define (hijos-tree tree) (cdr tree)) (define (hoja-tree? tree) (null? (hijos-tree tree))) El árbol anterior se puede construir con las siguientes instrucciones: (define tree (make-tree '* (list (make-tree '+ (list (make-hoja-tree 5) (make-tree '* (list (make-hoja-tre e 2) (make-hoja-tree 3))) (make-hoja-tree 10))) (make-tree '- (list (make-hoja-tree 12)))))) Cuando trabajamos con árboles genéricos y hacemos funciones recursivas que los recorren, es muy importante considerar en cada caso con qué tipo de dato estamos trabajando y usar la barrera de abstracción adecuada: La función hijos-tree devuelve una lista de árboles, que podemos recorrer usando car y cdr El car de una lista de árboles (devuelta por hijos-tree ) es un árbol y debemos de usar las funciones de su barrera de abstracción: dato-tree e hijos-tree La función dato-tree devuelve un dato de árbol, del tipo que guardemos en el árbol Por ejemplo, para obtener el número 2 en el árbol anterior habría que evaluar la siguiente expresión:

44 (dato-tree (car (hijos-tree (cadr (hijos-tree (car (hijos-tree tree)))))) ) Los árboles genéricos son listas estructuradas Si expresamos el árbol en forma de lista podemos comprobar que es una lista estructurada (* (+ (5) (* (2) (3)) (10)) (- (12))) De hecho, podríamos construirlo también utilizando directamente su formulación como una lista estructurada (aunque estaríamos rompiendo la barrera de abstracción). (define tree '(* (+ (5) (* (2) (3)) (10)) (- (12)))) Un árbol genérico de n hijos se implementa con una lista de n+1 elementos (el nodo de la raíz y sus n hijos). Un nodo hoja (árbol sin hijos) se implementa, por tanto, con una lista de un único elemento (el dato). En adelante vamos a utilizar esta forma de definir los árboles genéricos. Hay que hacer notar que un árbol binario no tiene la misma representación que un árbol genérico con dos hijos. Un árbol genérico con un único hijo no determina si el hijo está en la derecha o en la izquierda (que es fundamental en el árbol binario). Cómo se implementa el árbol de la siguiente figura como un árbol genérico y como un árbol binario? Árbol genérico:

45 (40 (18 (3) (23 (29))) (52 (47))) Árbol binario: (40 (18 (3 vacio-bt vacio-bt) (23 vacio-bt (29 vacio-bt vacio-bt))) (52 (47 vacio-bt vacio-bt) vacio-bt)) 5.2. Funciones recursivas Vamos a diseñar las siguientes funciones recursivas: (to-list-tree tree) : devuelve una lista con los datos del árbol (cuadrado-tree tree) : eleva al cuadrado todos los datos de un árbol manteniendo la estructura del árbol original (map-tree f tree) : devuelve un árbol con la estructura del árbol original aplicando la función f a subdatos. (niveles-tree tree) : devuelve el número de niveles de un árbol Todas comparten un patrón similar de recursión mutua (to-list-tree tree) Queremos diseñar una función (to-list-tree tree) que devuelva una lista con los datos del árbol en un recorrido inorden. (define (to-list-tree tree) (cons (dato-tree tree) (to-list-bosque (hijos-tree tree)))) (define (to-list-bosque bosque) (if (null? bosque) '() (append (to-list-tree (car bosque)) (to-list-bosque (cdr bosque))))) La función utiliza una recursión mutua: para listar todos los nodos, añadimos el dato a la lista de nodos que nos devuelve la función to-list-bosque. Esta función coge una lista de árboles (un bosque) y devuelve la lista inorden de sus nodos. Para ello, concatena la lista de

46 los nodos de su primer elemento (el primer árbol) a la lista de nodos del resto de árboles (que devuelve la llamada recursiva). Ejemplo: (to-list-tree '(* (+ (5) (* (2) (3)) (10)) (- (12)))) (* + 5 * ) Una definición alternativa usando funciones de orden superior: (define (to-list-tree tree) (if (null? (hijos-tree tree)) (list (dato-tree tree)) (cons (dato-tree tree) (apply append (map to-list-tree (hijos-tree tree)))))) Esta versión es muy elegante y concisa. Usa la función map que aplica una función a los elementos de una lista y devuelve la lista resultante. Como lo que devuelve (hijos-tree tree) es precisamente una lista de árboles podemos aplicar a sus elementos cualquier función definida sobre árboles. Incluso la propia función que estamos definiendo ( confía en la recursión!) (cuadrado-tree tree) Veamos ahora la función (cuadrado-tree tree) que toma un árbol de números y devuelve un árbol con la misma estructura y sus datos elevados al cuadrado: (define (cuadrado-tree tree) (make-tree (cuadrado (dato-tree tree)) (cuadrado-bosque (hijos-tree tree)))) (define (cuadrado-bosque bosque) (if (null? bosque) '() (cons (cuadrado-tree (car bosque)) (cuadrado-bosque (cdr bosque))))) Ejemplo: (cuadrado-tree '(2 (3 (4) (5)) (6))) (4 (9 (16) (25)) (36)) Versión 2, con map :

Tema 4: Procedimientos y estructuras recursivas

Tema 4: Procedimientos y estructuras recursivas Tema 4: Procedimientos y estructuras recursivas Contenidos 1. Recursión 1.1 Pensando recursivamente 1.2 El coste de la recursión 1.3 Soluciones al coste de la recursión: procesos iterativos 1.4 Soluciones

Más detalles

Tema 6: Estructuras de datos recursivas

Tema 6: Estructuras de datos recursivas Tema 6: Estructuras de datos recursivas Índice 1 Listas jerárquicas...2 2 Árboles binarios... 4 3 Árboles genéricos...7 4 Referencias...10 1. Listas jerárquicas Las listas tienen la propiedad de la clausura

Más detalles

Tema 10: Tipos de datos mutables

Tema 10: Tipos de datos mutables Índice 1 Introducción... 2 2 Primitivas set-car! y set-cdr!...2 2.1 Como implementar cons, set-car! y set-cdr!...3 3 Mutación... 3 4 Igualdad...6 5 TADs con datos mutables... 9 5.1 Lista ordenada... 9

Más detalles

Tema 3: Recursión. Índice

Tema 3: Recursión. Índice Índice 1 Recursión... 2 2 Confía en la recursión... 2 3 El coste espacial de la recursión... 5 4 Procesos recursivos e iterativos... 7 4.1 Ejemplos...10 5 Referencias...12 1. Recursión Ya hemos visto algunos

Más detalles

Tema 3. Listas Recursión sobre datos

Tema 3. Listas Recursión sobre datos Tema 3 Listas Recursión sobre datos José A. Alonso M. José Hidalgo Álvaro Romero Dpto. Ciencias de la Computación e Inteligencia Artificial UNIVERSIDAD DE SEVILLA Informática ListasRecursión sobre datos

Más detalles

Aplicación de la Inducción Matemática Programación Funcional. Julio Ariel Hurtado Alegría Departamento de Sistemas Universidad del Cauca

Aplicación de la Inducción Matemática Programación Funcional. Julio Ariel Hurtado Alegría Departamento de Sistemas Universidad del Cauca Aplicación de la Inducción Matemática Programación Funcional Julio Ariel Hurtado Alegría Departamento de Sistemas Universidad del Cauca Motivación Programación Imperativa Declarativa Procedimental Ejemplo:

Más detalles

Tema 4.- Recursión e iteración

Tema 4.- Recursión e iteración UNIVERSIDAD DE CÓRDOBA ESCUELA POLITÉCNICA SUPERIOR DE CÓRDOBA DEPARTAMENTO DE INFORMÁTICA Y ANÁLISIS NUMÉRICO PROGRAMACIÓN DECLARATIVA INGENIERÍA INFORMÁTICA ESPECIALIDAD DE COMPUTACIÓN CUARTO CURSO PRIMER

Más detalles

Tipos algebraicos y abstractos. Algoritmos y Estructuras de Datos I. Tipos algebraicos

Tipos algebraicos y abstractos. Algoritmos y Estructuras de Datos I. Tipos algebraicos Algoritmos y Estructuras de Datos I 1 cuatrimestre de 009 Departamento de Computación - FCEyN - UBA Programación funcional - clase Tipos algebraicos Tipos algebraicos y abstractos ya vimos los tipos básicos

Más detalles

Tema 2: Introducción a Scheme. Sesión 4: Introducción a Scheme (2)

Tema 2: Introducción a Scheme. Sesión 4: Introducción a Scheme (2) Tema 2: Introducción a Scheme Sesión 4: Introducción a Scheme (2) Referencias DrRacket (http://racket-lang.org/) A brief tour of DrScheme (http://www.plt-scheme.org/software/drscheme/ tour/) Structure

Más detalles

Estructura de datos y de la información Boletín de problemas - Tema 10

Estructura de datos y de la información Boletín de problemas - Tema 10 Estructura de datos y de la información Boletín de problemas - Tema 10 1. En el caso de que sea posible, dar un ejemplo de los siguientes puntos. Si no, explicar por qué no lo es. Considerar un valor genérico

Más detalles

Lenguajes de Programación Programación funcional

Lenguajes de Programación Programación funcional Lenguajes de Programación Programación funcional Roberto Bonvallet Departamento de Informática Universidad Técnica Federico Santa María Concepto de función En el paradigma imperativo: Una función es una

Más detalles

Tema 3: Características de la programación funcional. Sesión 6: El paradigma funcional (2)

Tema 3: Características de la programación funcional. Sesión 6: El paradigma funcional (2) Tema 3: Características de la programación funcional Sesión 6: El paradigma funcional (2) Referencias Capítulo 1.1.5 SICP: [[http://mitpress.mit.edu/sicp/full-text/book/book-z- H-10.html#%_sec_1.1.5][The

Más detalles

PROGRAMACIÓN DECLARATIVA

PROGRAMACIÓN DECLARATIVA UNIVERSIDAD DE CÓRDOBA ESCUELA POLITÉCNICA SUPERIOR DE CÓRDOBA DEPARTAMENTO DE INFORMÁTICA Y ANÁLISIS NUMÉRICO PROGRAMACIÓN DECLARATIVA INGENIERÍA INFORMÁTICA CUARTO CURSO PRIMER CUATRIMESTRE Tema 5.-

Más detalles

4.3 Recursión en Scheme. Recursión simple y asignación

4.3 Recursión en Scheme. Recursión simple y asignación 4.3 Recursión en Scheme Recursión simple y asignación Recursión Simple Un procedimiento recursivo es aquel se aplica a si mismo. Ejemplo: (define length (lambda (ls (if (null? ls 0 (+ 1 (length (cdr ls

Más detalles

4.3 Recursión en Scheme

4.3 Recursión en Scheme 4.3 Recursión en Scheme Recursión simple y asignación Recursión Simple Un procedimiento recursivo es aquel se aplica a si mismo. Ejemplo: (define length (lambda (ls (if (null? ls 0 (+ 1 (length (cdr ls

Más detalles

Programación Funcional Lisp-Scheme

Programación Funcional Lisp-Scheme Programación Funcional Lisp-Scheme Dr. Oldemar Rodríguez Rojas Escuela de Informática Universidad de Nacional Dónde bajar? Lisp (EdScheme): www.schemers.com com Ejemplo: => (+ (* 3(+ (* 24) (+ 35))) (+

Más detalles

Abstracción de procedimientos

Abstracción de procedimientos Abstracción de procedimientos 1.- Consideremos ABN (árboles binarios numéricos) sin nodos repetidos. Denimos los siguientes conceptos: Se pide: Dados dos ABN, A y B, decimos que B es SUBARBOL PRINCIPAL

Más detalles

Tema 4: Programación funcional avanzada en Scheme

Tema 4: Programación funcional avanzada en Scheme Tema 4: Programación funcional avanzada en Scheme Índice 1 Let... 2 2 Let*... 5 3 Letrec... 5 4 Quote...6 5 Eval... 7 6 Datos compuestos: parejas...8 7 Los datos compuestos pueden ser funciones...11 8

Más detalles

Ejercicio 2 Considere la representación para Lista de Naturales y Árbol Binario de Naturales de la Figura 1.

Ejercicio 2 Considere la representación para Lista de Naturales y Árbol Binario de Naturales de la Figura 1. Ejercicios Resueltos del Práctico 4 Ejercicio 2 Considere la representación para Lista de Naturales y Árbol Binario de Naturales de la Figura 1. 1 2 struct NodoLista { 3 int elem ; 4 NodoLista * sig ;

Más detalles

CONCEPTO Y DEFINICIÓN DE CLASE EN JAVA. OBJETOS DEL MUNDO REAL Y ABSTRACTOS. EJEMPLOS. EJERCICIO (CU00644B)

CONCEPTO Y DEFINICIÓN DE CLASE EN JAVA. OBJETOS DEL MUNDO REAL Y ABSTRACTOS. EJEMPLOS. EJERCICIO (CU00644B) APRENDERAPROGRAMAR.COM CONCEPTO Y DEFINICIÓN DE CLASE EN JAVA. OBJETOS DEL MUNDO REAL Y ABSTRACTOS. EJEMPLOS. EJERCICIO (CU00644B) Sección: Cursos Categoría: Curso Aprender programación Java desde cero

Más detalles

GUÍA BÁSICA DE SCHEME v.4

GUÍA BÁSICA DE SCHEME v.4 Esta guía básica pretende ser una introducción elemental al lenguaje de programación Scheme. Se presenta como una guía de comienzo rápido de tal forma que permita conocer de una forma muy esquemática los

Más detalles

Tema 5.- Tipos de datos compuestos

Tema 5.- Tipos de datos compuestos UNIVERSIDAD DE CÓRDOBA ESCUELA POLITÉCNICA SUPERIOR DE CÓRDOBA DEPARTAMENTO DE INFORMÁTICA Y ANÁLISIS NUMÉRICO PROGRAMAC CIÓN DECLARATIVA INGENIERÍA INFORMÁTICA ESPECIALIDAD DE COMPUTACIÓN CUARTO CURSO

Más detalles

n! = 1 2 n 0! = 1 (n+1)! = (n + 1) n!

n! = 1 2 n 0! = 1 (n+1)! = (n + 1) n! Capítulo 3 Recursión La recursión es un estilo autoreferencial de definición usado tanto en matemática como en informática. Es una herramienta de programación fundamental, particularmente importante para

Más detalles

CAPÍTULO IV: 4.1 Introducción a la. Programación Funcional

CAPÍTULO IV: 4.1 Introducción a la. Programación Funcional CAPÍTULO IV: Programación Funcional 4.1 Introducción a la Programación Funcional 1 Programación Funcional Paradigma diferente a los imperativos, que se aleja de la máquina de von Neumann Basado en funciones

Más detalles

Recursión. Introducción a la Computación Clase 15 Patricia Borensztejn

Recursión. Introducción a la Computación Clase 15 Patricia Borensztejn Recursión Introducción a la Computación Clase 15 Patricia Borensztejn El concepto de la recursión Recursión, recurrencia o recursividad es la forma en la cual se especifica un proceso basado en su propia

Más detalles

95.12 Algoritmos y Programación II Práctica 7: árboles

95.12 Algoritmos y Programación II Práctica 7: árboles Notas preliminares 95.12 Algoritmos y Programación II Práctica 7: árboles El objetivo de esta práctica es introducir distintas clases de estructuras de datos arbóreas y algoritmos para manipularlas. Los

Más detalles

Programación Declarativa

Programación Declarativa Programación Declarativa Tema 2: LISP (SCHEME) 2 Tema 2: LISP (SCHEME) Introducción Representación de Datos Definición de Funciones Predicados Listas 3 Introducción (I) SCHEME es un dialecto de LISP (LISt

Más detalles

4.1 Definición. Se dice que algo es recursivo si se define en función de sí mismo o a sí mismo. Un objeto (problemas, estructuras de datos) es

4.1 Definición. Se dice que algo es recursivo si se define en función de sí mismo o a sí mismo. Un objeto (problemas, estructuras de datos) es Recursividad 4.1 Definición. Se dice que algo es recursivo si se define en función de sí mismo o a sí mismo. Un objeto (problemas, estructuras de datos) es recursivo si forma parte de sí mismo o interviene

Más detalles

ESTRUCTURA DE DATOS Y ALGORITMOS Titulación: Ingeniero Técnico en Informática de Gestión Curso: 2º Nombre y apellidos: Nota:

ESTRUCTURA DE DATOS Y ALGORITMOS Titulación: Ingeniero Técnico en Informática de Gestión Curso: 2º Nombre y apellidos: Nota: Nombre y apellidos: Nota: Escribe tu nombre y apellidos en esta hoja e inmediatamente en todas las suplementarias, incluso las de sucio. El no hacerlo puede suponer tu expulsión Puedes utilizar el lápiz

Más detalles

Programación 2 Práctico 9 - TADs Árbol Binario de Búsqueda, Árbol Finitario y Árbol n-ario

Programación 2 Práctico 9 - TADs Árbol Binario de Búsqueda, Árbol Finitario y Árbol n-ario Práctico - TADs Árbol Binario de Búsqueda, Árbol Finitario y Árbol n-ario Objetivos Trabajar con los tipos abstractos de datos Árbol Binario de Búsqueda, Árbol Finitario y Árbol n-ario. Desarrollar y analizar

Más detalles

Procedimientos Definidos Localmente

Procedimientos Definidos Localmente Capítulo 5 Procedimientos Definidos Localmente 5.1 Distinguiendo entre definiciones globales ylocales Todas las primitivas (o procedimientos) disponibles en Scheme (p.ej., car, cons, cdr, etc.) se definen

Más detalles

Tema 3: Características de la programación funcional

Tema 3: Características de la programación funcional Tema 3: Características de la programación funcional Sesión 5: El paradigma funcional (1) martes 22 de febrero de 2011 Referencias Capítulo 1.1.5 SICP: [[http://mitpress.mit.edu/sicp/full-text/book/book-z-

Más detalles

ESTRUCTURAS DE DATOS Y ALGORITMOS

ESTRUCTURAS DE DATOS Y ALGORITMOS ESTRUCTURAS DE DATOS Y ALGORITMOS CURSO 2009 PRÁCTICO 8 Nota: al igual que en los prácticos 6 y 7, en los problemas que siguen se usarán los tipos lista y árbol binario, como tipos abstractos, cada uno

Más detalles

Complejidad de algoritmos recursivos

Complejidad de algoritmos recursivos Tema 3. Complejidad de algoritmos recursivos 1. INTRODUCCIÓN... 1 CLASIFICACIÓN DE FUNCIONES RECURSIVAS... 1 DISEÑO DE FUNCIONES RECURSIVAS... 2 2. VENTAJAS E INCONVENIENTES DE LA RECURSIVIDAD... 4 3.

Más detalles

Tema 3: Programación funcional

Tema 3: Programación funcional Tema 3: Programación funcional Contenidos 5. Funciones como tipos de datos de primera clase 5.1. Forma especial lambda 5.2. Las funciones son objetos de primera clase 5.3. Funciones de orden superior 6.

Más detalles

4.7 Operaciones sobre Objetos en Scheme

4.7 Operaciones sobre Objetos en Scheme 4.7 Operaciones sobre Objetos en Scheme Equivalencias y predicados de tipos, listas, números, caracteres, strings y vectores Ejemplos de Equivalencia (eq? a a) ;=> #t (eq? 3.1 3.1) ;=> () (eq? (cons a

Más detalles

Tema 9: Asignación, estado local y modelo de entornos

Tema 9: Asignación, estado local y modelo de entornos Tema 9: Asignación, estado local y modelo de entornos Índice 1 Programación imperativa... 2 2 Formas especiales set!...3 3 Entornos... 3 4 Estado local...8 4.1 Ejemplo 1: contador global... 8 4.2 Ejemplo

Más detalles

4.7 Operaciones sobre Objetos en Scheme. Equivalencias y predicados de tipos, listas, números, caracteres, strings y vectores

4.7 Operaciones sobre Objetos en Scheme. Equivalencias y predicados de tipos, listas, números, caracteres, strings y vectores 4.7 Operaciones sobre Objetos en Scheme Equivalencias y predicados de tipos, listas, números, caracteres, strings y vectores a) Equivalencias (eq? obj 1 obj 2 ) retorno: #t si son idénticos (eqv? obj 1

Más detalles

Tema 7: Programación imperativa. Sesión 21: Programación imperativa (2)

Tema 7: Programación imperativa. Sesión 21: Programación imperativa (2) Tema 7: Programación imperativa Sesión 21: Programación imperativa (2) Indice Historia de la programación imperativa Características principales Datos mutables en Scheme y en Scala Estructuras de control

Más detalles

Estructuras de datos y algoritmos

Estructuras de datos y algoritmos Estructuras de datos y algoritmos 1. Introducción 2. Estructuras de datos lineales 3. Estructuras de datos jerárquicas 4. Grafos y caminos 5. Implementación de listas, colas, y pilas 6. Implementación

Más detalles

Estructuras de Datos y de la Información Ingeniería Técnica en Informática de Gestión. Curso 2007/2008 Ejercicios del Tema 2

Estructuras de Datos y de la Información Ingeniería Técnica en Informática de Gestión. Curso 2007/2008 Ejercicios del Tema 2 Estructuras de Datos y de la Información Ingeniería Técnica en Informática de Gestión. Curso 2007/2008 Ejercicios del Tema 2 Diseño de algoritmos recursivos 1. Dado un vector de enteros de longitud N,

Más detalles

Algoritmos y Estructuras de Datos: Introducción a la Recursión de Programas. Guillermo Román Díez

Algoritmos y Estructuras de Datos: Introducción a la Recursión de Programas. Guillermo Román Díez Algoritmos y Estructuras de Datos: Introducción a la Recursión de Programas Guillermo Román Díez groman@fi.upm.es Universidad Politécnica de Madrid Curso 2015-2016 Guillermo Román, UPM AED: Introducción

Más detalles

Ejercicios Scheme. Para cada función escriba su contrato, descripción, ejemplos y los tests necesarios, antes de su implementación.

Ejercicios Scheme. Para cada función escriba su contrato, descripción, ejemplos y los tests necesarios, antes de su implementación. Ejercicios Scheme Para cada función escriba su contrato, descripción, ejemplos y los tests necesarios, antes de su implementación. 1 Para soltar la mano 1. Represente la siguiente expresión en Scheme:

Más detalles

ESTRUCTURA DE DATOS Y ALGORITMOS Titulación: Ingeniero Técnico en Informática de Gestión Curso: 2º Nombre y apellidos: Nota:

ESTRUCTURA DE DATOS Y ALGORITMOS Titulación: Ingeniero Técnico en Informática de Gestión Curso: 2º Nombre y apellidos: Nota: Nombre y apellidos: Nota: NOTA FINAL: Nota Practica (1 punto) + Nota Examen (9 punto) Es indispensable aprobar el examen (4,5 puntos) para aprobar la asignatura (5 puntos) La práctica es opcional Duración:

Más detalles

UNIVERSIDAD NACIONAL AUTÓNOMA DE MÉXICO

UNIVERSIDAD NACIONAL AUTÓNOMA DE MÉXICO Introducción Un árbol es una estructura no lineal en la que cada nodo puede apuntar a uno o varios nodos. A B C D E F G H I J K Clasificación con respecto a su relación: Nodo hijo: cualquiera de los nodos

Más detalles

Ejercicios sobre recursividad

Ejercicios sobre recursividad Ejercicios sobre recursividad 11 de febrero de 2003 1. Implementa una función recursiva que devuelva la suma de los dígitos de un número natural, que se le pasa por parámetro. 2. Implementa una función

Más detalles

Informática de 1 o de Matemáticas. Ejercicios de Introducción a Haskell. Ejercicio 1 Consideremos la siguiente definición:

Informática de 1 o de Matemáticas. Ejercicios de Introducción a Haskell. Ejercicio 1 Consideremos la siguiente definición: Ejercicios de Introducción a Haskell Informática de 1 o de Matemáticas Ejercicio 1 Consideremos la siguiente definición: doble x = x + x El valor de doble(doble 3) se puede calcular usando distintos métodos

Más detalles

A) PREORDEN B) INORDEN C) POSTORDEN D) NIVELES

A) PREORDEN B) INORDEN C) POSTORDEN D) NIVELES Capitulo 5. Arboles 1. Al recorrer el siguiente árbol en se visitan más nodos para llegar al número 38. Justifique su respuesta mostrando cada uno de los recorridos. Tipo de Recorrido Recorrido A) PREORDEN

Más detalles

Tipos de datos en Haskell

Tipos de datos en Haskell Tipos de datos en Haskell Ejercicios 1. Tipos enumerados Cuando los distintos valores que debemos distinguir en un tipo son finitos, entonces podemos enumerar todos los valores distintos para el tipo.

Más detalles

Tema 9: Asignación, estado local y modelo de entornos

Tema 9: Asignación, estado local y modelo de entornos Tema 9: Asignación, estado local y modelo de entornos Índice 1 Programación imperativa... 2 2 Formas especiales set!...3 3 La forma especial begin... 3 4 Entornos... 4 5 El modelo de computación de Scheme

Más detalles

1.1 Define un operador ( ) que devuelva True si y solo si tan solo uno de sus argumentos es True. Por ejemplo:? (3 > 2) (2 > 5)

1.1 Define un operador ( ) que devuelva True si y solo si tan solo uno de sus argumentos es True. Por ejemplo:? (3 > 2) (2 > 5) 1 Informática Haskell Matemáticas Curso 2004-2005 Pepe Gallardo Universidad de Málaga Práctica 1 1.1 Define un operador ( ) que devuelva True si y solo si tan solo uno de sus argumentos es True. Por ejemplo:?

Más detalles

Práctica 5.- Recursividad

Práctica 5.- Recursividad Benemérita Universidad Autónoma de Puebla Facultad de Ciencias de la Computación Programación Avanzada en Java Prim. 2009 Práctica 5.- Recursividad Datos de la práctica Fecha 6 de marzo de 2009 Conceptos

Más detalles

4.5 Ligado de Variables en Scheme

4.5 Ligado de Variables en Scheme 4.5 Ligado de Variables en Scheme Referencia a variables, lambda, formas let y asignación a) Referencia a una Variable variable retorno: valor de la variable Cualquier identificador no citada en una expresión

Más detalles

Guía 2: Listas, recursión e inducción

Guía 2: Listas, recursión e inducción Introducción a los Algoritmos - 2do cuatrimestre 2014 Guía 2: Listas, recursión e inducción Docentes: Walter Alini, Luciana Benotti En esta guía comenzaremos a trabajar con listas Para familiarizarnos

Más detalles

Algoritmos y programas. Algoritmos y Estructuras de Datos I

Algoritmos y programas. Algoritmos y Estructuras de Datos I Algoritmos y programas Algoritmos y Estructuras de Datos I Primer cuatrimestre de 2012 Departamento de Computación - FCEyN - UBA Programación funcional - clase 1 Funciones Simples - Recursión - Tipos de

Más detalles

Secuencias en Python. Introducción a la Computación Clase 11 Patricia Borensztejn

Secuencias en Python. Introducción a la Computación Clase 11 Patricia Borensztejn Secuencias en Python Introducción a la Computación Clase 11 Patricia Borensztejn Una cadena es una secuencia En Python tenemos los tipos de datos Escalares: enteros, flotantes Secuencias: sucesión de elementos

Más detalles

Instituto de Computación. Facultad de Ingeniería. Universidad de la República Examen de Programación 2 03 de Agosto de 2006 Generalidades:

Instituto de Computación. Facultad de Ingeniería. Universidad de la República Examen de Programación 2 03 de Agosto de 2006 Generalidades: Instituto de Computación. Facultad de Ingeniería. Universidad de la República Examen de Programación 2 03 de Agosto de 2006 Generalidades: La prueba es individual y sin material. La duración es 3 horas.

Más detalles

Teoría de los Lenguajes de Programación Práctica curso

Teoría de los Lenguajes de Programación Práctica curso Teoría de los Lenguajes de Programación Práctica curso 2013-2014 Índice 1. Introducción: Sumas...3 2. Enunciado de la práctica...3 2.1 Método de Resolución...3 Generación de los nodos...4 Función Principal...5

Más detalles

Estructura de Datos. Temario Unidad VI. Árboles Árboles Binarios

Estructura de Datos. Temario Unidad VI. Árboles Árboles Binarios Estructura de Datos Árboles Árboles Binarios Temario Unidad VI 6.1 Definición y operaciones 6.2 Implementación 6.3 Recorrido en Árboles Binarios 6.4 Árboles AVL y su implementación 6.5 Árboles n-arios

Más detalles

El TAD Árbol. El TAD Árbol

El TAD Árbol. El TAD Árbol Objetivos! Presentar el árbol como estructura de datos jerárquica! Estudiar diferentes variantes de árboles, tanto en su especificación como en su implementación Contenidos 3.1 Concepto, definiciones y

Más detalles

Sólo una opción es correcta en cada pregunta. Cada respuesta correcta suma 1 4. puntos. Cada respuesta incorrecta resta 1 12

Sólo una opción es correcta en cada pregunta. Cada respuesta correcta suma 1 4. puntos. Cada respuesta incorrecta resta 1 12 Programación de Sistemas Grados en Ingeniería de Sistemas Audiovisuales, Ingeniería de Sistemas de Comunicaciones, Ingeniería en Sistemas de Telecomunicación e Ingeniería Telemática Leganés, de julio de

Más detalles

ÁRBOLES CRISTIAN ALFREDO MUÑOZ ÁLVAREZ JUAN DAVID LONDOÑO CASTRO JUAN PABLO CHACÓN PEÑA EDUARDO GONZALES

ÁRBOLES CRISTIAN ALFREDO MUÑOZ ÁLVAREZ JUAN DAVID LONDOÑO CASTRO JUAN PABLO CHACÓN PEÑA EDUARDO GONZALES ÁRBOLES CRISTIAN ALFREDO MUÑOZ ÁLVAREZ JUAN DAVID LONDOÑO CASTRO JUAN PABLO CHACÓN PEÑA EDUARDO GONZALES ÁRBOL Un árbol es un grafo no dirigido, conexo, sin ciclos (acíclico), y que no contiene aristas

Más detalles

UNIDAD 7 Recursividad Concepto. Algoritmos recursivos. Seguimiento de la recursión. Algunos métodos recursivos de búsqueda y ordenación: M-Sort y

UNIDAD 7 Recursividad Concepto. Algoritmos recursivos. Seguimiento de la recursión. Algunos métodos recursivos de búsqueda y ordenación: M-Sort y Recursividad Concepto. Algoritmos recursivos. Seguimiento de la recursión. Algunos métodos recursivos de búsqueda y ordenación: M-Sort y Q-Sort. Comparación de eficiencia en métodos Iterativos vs recursivos

Más detalles

Metodología de la Programación II. Recursividad

Metodología de la Programación II. Recursividad Metodología de la Programación II Recursividad Objetivos Entender el concepto de recursividad. Conocer los fundamentos del diseño de algoritmos recursivos. Comprender la ejecución de algoritmos recursivos.

Más detalles

EDA. Tema 8 Colas de Prioridad: Heaps

EDA. Tema 8 Colas de Prioridad: Heaps EDA. Tema 8 Colas de Prioridad: Heaps Natividad Prieto Sáez. DSIC EDA, T-8. Curso 02/03. N.Prieto p.1/55 Objetivos Estudio de las definiciones asociadas a las Colas de Prioridad: Especificación: operaciones

Más detalles

Fundamentos de la POO 1

Fundamentos de la POO 1 Fundamentos de la POO 1 La correcta aplicación de los conocimientos de clases y objetos nos permitirán llegar a los objetivos planteados y a generar programas que puedan ser fáciles de comprender para

Más detalles

Versión Iterativa de recuperar en un. Ejercicios Tema 11. Implementa una versión del método recuperar iterativa con la siguiente especificación:

Versión Iterativa de recuperar en un. Ejercicios Tema 11. Implementa una versión del método recuperar iterativa con la siguiente especificación: Versión Iterativa de recuperar en un ABB Ejercicios Tema 11 Ejercicios Adaptados de Apuntes y Exámenes de EDA Germán Moltó Martínez gmolto@dsic.upv.es Estructuras de Datos y Algoritmos Escuela Técnica

Más detalles

FUNDAMENTOS DE PROGRAMACIÓN Datos recursivos II

FUNDAMENTOS DE PROGRAMACIÓN Datos recursivos II FUNDAMENTOS DE PROGRAMACIÓN Datos recursivos II Ángela Villota Gómez Escuela de Ingeniería de Sistemas y Computación Facultad de Ingeniería Universidad del Valle Primera parte: Repaso de funciones con

Más detalles

Tipos de datos algebraicos

Tipos de datos algebraicos Tipos de datos algebraicos Taller de Álgebra I Segundo cuatrimestre de 2013 Programación funcional Recordemos que un tipo de datos es un conjunto dotado con una serie de operaciones sobre los elementos

Más detalles

ARBOLES BINARIOS ORDENADOS. REPRESENTACIÓN Y OPERACIONES

ARBOLES BINARIOS ORDENADOS. REPRESENTACIÓN Y OPERACIONES ARBOLES BINARIOS ORDENADOS. REPRESENTACIÓN Y OPERACIONES TEMAS Recorrido de un árbol Máximo y mínimo Búsqueda de un elemento Borrado de un nodo 3 Características ARBOLES - CONCEPTOS Cada elemento del árbol

Más detalles

Estructura de datos y de la información Boletín de problemas - Tema 9

Estructura de datos y de la información Boletín de problemas - Tema 9 Estructura de datos y de la información Boletín de problemas - Tema 9 1. Dada la siguiente función recursiva: void F(char c) { if (( A

Más detalles

Tema 3.- Predicados y sentencias condicionales

Tema 3.- Predicados y sentencias condicionales UNIVERSIDAD DE CÓRDOBA ESCUELA POLITÉCNICA SUPERIOR DE CÓRDOBA DEPARTAMENTO DE INFORMÁTICA Y ANÁLISIS NUMÉRICO PROGRAMACIÓN DECLARATIVA INGENIERÍA INFORMÁTICA ESPECIALIDAD DE COMPUTACIÓN CUARTO CURSO PRIMER

Más detalles

Examen escrito de Programación 1

Examen escrito de Programación 1 Examen escrito de Programación 1 Escuela de Ingeniería y Arquitectura Departamento de Informática e Ingeniería de Sistemas 31 de agosto de 2012 Disponer sobre la mesa en lugar visible un documento de identificación

Más detalles

Benemérita Universidad Autónoma de Puebla Facultad de Ciencias de la Computación Área de Programación

Benemérita Universidad Autónoma de Puebla Facultad de Ciencias de la Computación Área de Programación Asignatura: Programación I Fecha: Marzo 2012 Benemérita Universidad Autónoma de Puebla Facultad de Ciencias de la Computación Área de Programación Funciones 1. Escriba un programa en C que intercambie

Más detalles

SEMINARIO DE ESPECIFICACIONES ALGEBRAICAS

SEMINARIO DE ESPECIFICACIONES ALGEBRAICAS Algoritmos y Estructuras de Datos Ingeniería en Informática, Curso 2º, Año 2003/2004 SEMINARIO DE ESPECIFICACIONES ALGEBRAICAS Contenidos: 1. Descripción general de Maude 2. Comandos básicos 3. Formato

Más detalles

GENERACIÓN DE CÓDIGO INTERMEDIO EJEMPLOS PARA DISTINTAS ESTRUCTURAS DE DATOS

GENERACIÓN DE CÓDIGO INTERMEDIO EJEMPLOS PARA DISTINTAS ESTRUCTURAS DE DATOS Todos los derechos de propiedad intelectual de esta obra pertenecen en exclusiva a la Universidad Europea de Madrid, S.L.U. Queda terminantemente prohibida la reproducción, puesta a disposición del público

Más detalles

Programación Funcional Lisp-DrScheme Primera Parte. Dr. Oldemar Rodríguez Rojas Escuela de Informática Universidad de Nacional

Programación Funcional Lisp-DrScheme Primera Parte. Dr. Oldemar Rodríguez Rojas Escuela de Informática Universidad de Nacional Programación Funcional Lisp-DrScheme Primera Parte Dr. Oldemar Rodríguez Rojas Escuela de Informática Universidad de Nacional Programación Funcional! La programación funcional es un paradigma de programación

Más detalles

Teoría de los Lenguajes de Programación Práctica curso Enunciado. Fernando López Ostenero y Ana García Serrano

Teoría de los Lenguajes de Programación Práctica curso Enunciado. Fernando López Ostenero y Ana García Serrano Teoría de los Lenguajes de Programación Práctica curso 2015-2016 Enunciado Fernando López Ostenero y Ana García Serrano Sumario 1. Introducción: Skyline de una ciudad...3 2. Enunciado de la práctica...3

Más detalles

Abstracción de Datos y

Abstracción de Datos y Capítulo 3 Abstracción de Datos y Números El cómputo numérico ha sido tradicionalmente ignorado por la comunidad de Lisp. Hasta antes del Common Lisp nadie había ideado una estrategia detallada para ordenar

Más detalles

Capítulo 3 Algoritmos recursivos

Capítulo 3 Algoritmos recursivos Capítulo 3 Algoritmos recursivos Los algoritmos recursivos se basan en la metodología de llamar repetidamente la propia función en que están definidos, y son de gran utilidad en multitud de campos en la

Más detalles

Recursividad Definición

Recursividad Definición Recursividad Definición Un procedimiento o función se dice recursivo si durante su ejecución se invoca directa o indirectamente a sí mismo. Esta invocación depende al menos de una condición que actúa como

Más detalles

Recursión. Recursión continuación

Recursión. Recursión continuación Recursión Recursión continuación Recursión Temas que veremos hoy Estructuras de control iterativas, repetitivas y la recursión. Ejemplos recursivos Búsqueda lineal Eficiencia y recursión Conclusiones Recursión

Más detalles

Estructuras de Datos y Algoritmos: Boletín de Problemas del segundo parcial

Estructuras de Datos y Algoritmos: Boletín de Problemas del segundo parcial Estructuras de Datos y Algoritmos: Boletín de Problemas del segundo parcial (Facultad de Informática) Curso 00 0 Estructuras de Datos y Algoritmos (FI-UPV) Curso 00 0 Árboles. Si la acción P fuera escribir

Más detalles

Modelos de Desarrollo de Programas Y Programación Concurrente Clase N 3

Modelos de Desarrollo de Programas Y Programación Concurrente Clase N 3 PROGRAMACION FUNCIONAL - Un lenguaje de programación funcional tiene gran flexibilidad, es conciso en su notación y su semántica es sencilla. El inconveniente principal de estos lenguajes ha sido la ineficiencia

Más detalles

Práctica N o 1 - Programación Funcional

Práctica N o 1 - Programación Funcional Práctica N o 1 - Programación Funcional Para resolver esta práctica, recomendamos usar el Hugs 98, de distribución gratuita, que puede bajarse de http://www.haskell.org/hugs/. Ejercicio 1 Dado el siguiente

Más detalles

2º Certamen ILI-253 Lenguajes de Programación Juan Pablo Menichetti Jorge Mujica 10 de Junio del 2004

2º Certamen ILI-253 Lenguajes de Programación Juan Pablo Menichetti Jorge Mujica 10 de Junio del 2004 º Certamen ILI-53 Lenguajes de Programación Juan Pablo Menichetti Jorge Mujica 10 de Junio del 004 ta: Tiempo: 10 Minutos. Responda con lápiz indeleble para acceder a recorrecciones. Utilice solo las hojas

Más detalles

PARTE II: ALGORÍTMICA

PARTE II: ALGORÍTMICA Programa de teoría Parte I. Estructuras de Datos.. Abstracciones y especificaciones.. Conjuntos y diccionarios.. Representación de conjuntos mediante árboles. 4. Grafos. Parte II. Algorítmica.. Análisis

Más detalles

Clase adicional 9. Listas enlazadas. Temas. Listas enlazadas Árboles Problemas de la clase adicional Ejercicios de diseño

Clase adicional 9. Listas enlazadas. Temas. Listas enlazadas Árboles Problemas de la clase adicional Ejercicios de diseño Clase adicional 9 Temas Listas enlazadas Árboles Problemas de la clase adicional Ejercicios de diseño Listas enlazadas Previamente en este curso, ya habrá trabajado con dos de las estructuras de datos

Más detalles

Algoritmos y Programación II Curso 2006

Algoritmos y Programación II Curso 2006 Arboles: Un árbol es una colección de elementos, llamados nodos, uno de los cuales se distingue con el nombre de raíz. Los nodos mantienen entre ellos una relación que define una estructura jerárquica

Más detalles

Programación Declarativa. Ingeniería Informática Especialidad de Computación Cuarto curso. Primer cuatrimestre

Programación Declarativa. Ingeniería Informática Especialidad de Computación Cuarto curso. Primer cuatrimestre Programación Declarativa Ingeniería Informática Especialidad de Computación Cuarto curso. Primer cuatrimestre Escuela Politécnica Superior de Córdoba Universidad de Córdoba Curso académico: 2013 2014 Práctica

Más detalles

Tema 7: Macros. Índice. 1 Introducción Conceptos previos Macros en Scheme Más ejemplos de macros Referencias...

Tema 7: Macros. Índice. 1 Introducción Conceptos previos Macros en Scheme Más ejemplos de macros Referencias... Índice 1 Introducción... 2 2 Conceptos previos...2 3 Macros en Scheme... 7 4 Más ejemplos de macros...10 5 Referencias...13 1. Introducción El primer párrafo del Revised5 Report on the Algorithmic Language

Más detalles

Tipos paramétricos y recursivos

Tipos paramétricos y recursivos Tipos paramétricos y recursivos Taller de Álgebra I Verano 2017 Tipos paramétricos Tipos paramétricos Podemos hacer que los constructores de un tipo de datos reciban parámetros. A los tipos construidos

Más detalles

Tema 7: Árbol Binario

Tema 7: Árbol Binario Apuntes elaborados por: Eduardo Quevedo, Aaron Asencio y Raquel López Revisado por: Javier Miranda el???? Tema 7: Árbol Binario En el árbol binario se combina lo mejor del array (acceso rápido a elementos,

Más detalles

ESTRUCTURA DE DATOS Y ALGORITMOS Titulación: Ingeniero Técnico en Informática de Gestión Curso: 2º Nombre y apellidos: Nota:

ESTRUCTURA DE DATOS Y ALGORITMOS Titulación: Ingeniero Técnico en Informática de Gestión Curso: 2º Nombre y apellidos: Nota: Nombre y apellidos: Nota: Escribe tu nombre y apellidos en esta hoja e inmediatamente en todas las suplementarias, incluso las de sucio. El no hacerlo puede suponer tu expulsión Puedes utilizar el lápiz

Más detalles

Secuencias Calculadas

Secuencias Calculadas Secuencias Calculadas Estructuras de Iteración y Recursividad Prof. Hilda Contreras Programación 1 hildac.programacion1@gmail.com Secuencias Calculadas Se aplican a los problemas donde los elementos de

Más detalles