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 3.1
Recursión sobre datos Contenido: Recursión plana. Recursión profunda. Recursión terminal. Informática ListasRecursión sobre datos 3.2
Recursión sobre listas: suma-elementos (suma-elementos (1 2 3 4)) => 10 (suma-elementos (5 1 3)) => 9 (suma-elementos ()) => 0 Algoritmo recursivo de suma-elementos: Entrada: L (lista numérica plana) SI L es la lista vacía ENTONCES devolver 0 EN CASO CONTRARIO devolver la suma de * el primer elemento de L y * el resultado de sumar los elementos del resto de L Informática ListasRecursión sobre datos 3.3
Recursión sobre listas: suma-elementos Definición del procedimiento suma-elementos: (define suma-elementos (lambda (l) (if (null? l) 0 (+ (car l) (suma-elementos (cdr l)))))) Informática ListasRecursión sobre datos 3.4
Traza de suma-elementos > (suma-elementos (1 2 3 4)) (suma-elementos (1 2 3 4)) (suma-elementos (2 3 4)) (suma-elementos (3 4)) (suma-elementos (4)) (suma-elementos ()) 0 4 7 9 10 10 Informática ListasRecursión sobre datos 3.5
Recursión sobre listas: ordenada? (ordenada? (2 2 5 6 8)) => #t (ordenada? (2 5 1 8)) => #f (ordenada? ()) => #t Algoritmo recursivo de ordenada?: Entrada: L (lista numérica plana) SI L es la lista vacía o tiene un sólo elemento ENTONCES devolver #t SI el primer elemento de L es mayor estricto que el segundo ENTONCES devolver #f EN OTRO CASO comprobar si los elementos del resto de L están en orden creciente Informática ListasRecursión sobre datos 3.6
Recursión sobre listas: ordenada? Definición del procedimiento ordenada?: (define ordenada? (lambda (l) (cond ((or (null? l) (null? (cdr l))) #t) ((> (car l) (cadr l)) #f) (else (ordenada? (cdr l)))))) Informática ListasRecursión sobre datos 3.7
Construcción de listas por recursión: suc-decreciente (suc-decreciente 0) => (0) (suc-decreciente 2) => (2 1 0) (suc-decreciente 6) => (6 5 4 3 2 1 0) Algoritmo recursivo de suc-decreciente: Entrada: N (número natural) SI N es el cero ENTONCES devolver la lista (0) EN OTRO CASO * añadir el número N a la lista obtenida al * construir la sucesión decreciente desde N-1 hasta 0 Informática ListasRecursión sobre datos 3.8
Construcción de listas por recursión: suc-decreciente Definición del procedimiento suc-decreciente: (define suc-decreciente (lambda (n) (if (zero? n) (0) (cons n (suc-decreciente ( n 1)))))) Traza de suc-decreciente: (suc-decreciente 2) (suc-decreciente 1) (suc-decreciente 0) (0) (1 0) (2 1 0) Informática ListasRecursión sobre datos 3.9
Construcción de listas por recursión: quita-primera (quita-primera a (c d a b a e)) => (c d b a e) (quita-primera a (c (a b) a d)) => (c (a b) d) (quita-primera a ()) => () (quita-primera a (1 2 3)) => (1 2 3) Algoritmo recursivo de quita-primera: Entrada: X (dato cualquiera) y L (lista) SI L es la lista vacía, devolver () SI el primer elemento de L es igual a X, devolver el resto de L EN OTRO CASO * añadir el primer elemento de L a la lista resultante de * eliminar la primera ocurrencia de X en el resto de L Informática ListasRecursión sobre datos 3.10
Construcción de listas por recursión: quita-primera Definición del procedimiento quita-primera: (define quita-primera (lambda (x l) (cond ((null? l) ()) ((equal? (car l) x) (cdr l)) (else (cons (car l) (quita-primera x (cdr l))))))) Informática ListasRecursión sobre datos 3.11
Construcción de listas por recursión: cambia (cambia a b (c d a b)) => (c d b b) (cambia a b (c d b a b (a c) f)) => (c d b b b (a c) f) Algoritmo recursivo de cambia: Entrada: X (dato cualquiera), Y (dato cualquiera) y L (lista) SI L es la lista vacía, devolver la lista vacía SI el primer elemento de L es igual a X * añadir Y a la lista resultante de * cambiar X por Y en el resto de L EN OTRO CASO * añadir el primer elemento de L a la lista resultante de * cambiar X por Y en el resto de L Informática ListasRecursión sobre datos 3.12
Construcción de listas por recursión: cambia Definición del procedimiento cambia: (define cambia (lambda (x y l) (cond ((null? l) ()) ((equal? (car l) x) (cons y (cambia x y (cdr l)))) (else (cons (car l) (cambia x y (cdr l))))))) Informática ListasRecursión sobre datos 3.13
Recursión plana: lugares-pares (lugares-pares (1 s 3 d f g 5)) => (s d g) (lugares-pares (1 (2) 3 4 5 (6 7))) => ((2) 4 (6 7)) (lugares-pares ()) => () (lugares-pares (uno)) => () Definición del procedimiento lugares-pares: (define lugares-pares (lambda (l) (if (or (null? l) (null? (cdr l))) () (cons (cadr l) (lugares-pares (cddr l)))))) Informática ListasRecursión sobre datos 3.14
Recursión plana: producto-escalar (producto-escalar (1 1 1) (1 2 3)) => 6 (producto-escalar (1 3 5 7) (8 6 4 2)) => 60 (producto-escalar () ()) => 0 Definición del procedimiento producto-escalar: (define producto-escalar (lambda (l1 l2) (if (null? l1) 0 (+ ( (car l1) (car l2)) (producto-escalar (cdr l1) (cdr l2)))))) Informática ListasRecursión sobre datos 3.15
Recursión profunda: suma-todos (suma-todos (1 2 3 4)) => 10 (suma-todos (1 (2) (3 (4)))) => 10 (suma-todos ()) => 0 Algoritmo recursivo de suma-todos: Entrada: L (lista numérica) SI L es la lista vacía, devolver 0 SI el primer elemento de L es una lista devolver la suma de * el resultado de sumar los números del primer elemento de L * el resultado de sumar los números del resto de L EN OTRO CASO devolver la suma de * el primer elemento de L y * el resultado de sumar los números del resto de L Informática ListasRecursión sobre datos 3.16
Recursión profunda: suma-todos Definición del procedimiento suma-todos: (define suma-todos (lambda (l) (cond ((null? l) 0) ((list? (car l)) (+ (suma-todos (car l)) (suma-todos (cdr l)))) (else (+ (car l) (suma-todos (cdr l))))))) Informática ListasRecursión sobre datos 3.17
Recursión profunda: cambia-todos (cambia-todos a b (c d a b)) => (c d b b) (cambia-todos a b (c d b a b (a c) f)) => (c d b b b (b c) f) (cambia-todos (0) 1 ((0) 0 ((0) 1 ()))) => (1 0 (1 1 ())) Definición del procedimiento cambia-todos: (define cambia-todos (lambda (x y l) (cond ((null? l) ()) ((equal? x (car l)) (cons y (cambia-todos x y (cdr l)))) ((pair? (car l)) (cons (cambia-todos x y (car l)) (cambia-todos x y (cdr l)))) (else (cons (car l) (cambia-todos x y (cdr l))))))) Informática ListasRecursión sobre datos 3.18
Recursión profunda: cuenta-parentesis (cuenta-parentesis ()) => 2 (cuenta-parentesis ((1) ((2)))) => 8 (cuenta-parentesis (() (a ()) (b () (c ())))) => 16 Definición del procedimiento cuenta-parentesis: (define cuenta-parentesis (lambda (l) (cond ((null? l) 2) ((list? (car l)) (+ (cuenta-parentesis (car l)) (cuenta-parentesis (cdr l)))) (else (cuenta-parentesis (cdr l)))))) Informática ListasRecursión sobre datos 3.19
Representación de listas mediante árboles (a (b (c)) ((d)) (e (f g))) +----+------+----------+ a (b (c)) ((d)) (e (f g)) Nivel 1 +--+--+ +----+----+ b (c) (d) e (f g) Nivel 2 +---+--+ c d f g Nivel 3 Informática ListasRecursión sobre datos 3.20
Listas y árboles: profundidad (profundidad (a b c)) => 1 (profundidad (a (b c) (d))) => 2 (profundidad (a (b (c)) ((d)) (e (f g)))) => 3 (profundidad a) => 0 (profundidad ()) => 0 Definición del procedimiento profundidad: (define profundidad (lambda (expr) (if (not (pair? expr)) 0 (max (+ 1 (profundidad (car expr))) (profundidad (cdr expr)))))) Informática ListasRecursión sobre datos 3.21
Listas y árboles: aplanar (aplanar ((a ((b c))) d ((e) f))) => (a b c d e f) (aplanar (a (b ()) ())) => (a b) (aplanar ()) => () Definición del procedimiento aplanar: (define aplanar (lambda (l) (cond ((null? l) ()) ((list? (car l)) (append (aplanar (car l)) (aplanar (cdr l)))) (else (cons (car l) (aplanar (cdr l))))))) Informática ListasRecursión sobre datos 3.22
Recursión terminal: fact-it (fact-it 3) => 6 (fact-it 5) => 120 Definición del procedimiento fact-it: (define fact-it (lambda (n) (fact-it-aux n 1))) (define fact-it-aux (lambda (n acumulador) (if (zero? n) acumulador (fact-it-aux ( n 1) ( n acumulador))))) Informática ListasRecursión sobre datos 3.23
Tabla y traza de fact-it-aux Tabla: n acumulador 4 1 3 4 2 12 1 24 0 24 Traza: > (fact-it 4) (fact-it-aux 4 1) (fact-it-aux 3 4) (fact-it-aux 2 12) (fact-it-aux 1 24) (fact-it-aux 0 24) 24 24 24 24 24 24 Informática ListasRecursión sobre datos 3.24
Recursión-terminal: suma-elementos-it (suma-elementos-it (1 2 3 4)) => 10 (suma-elementos-it (5 1 3)) => 9 (suma-elementos-it ()) => 0 Definición del procedimiento suma-elementos-it: (define suma-elementos-it (lambda (lista) (suma-elementos-it-aux lista 0))) (define suma-elementos-it-aux (lambda (l ac) (if (null? l) ac (suma-elementos-it-aux (cdr l) (+ ac (car l)))))) Informática ListasRecursión sobre datos 3.25
Recursión terminal: cambia-it (cambia-it a b (c d a b a c f)) => (c d b b b c f) (cambia-it a b (c d a b)) => (c d b b) (cambia-it a b (c d b a b (a c) f)) => (c d b b b (a c) f) Definición del procedimiento cambia-it: (define cambia-it (lambda (x y l) (cambia-it-aux x y l ()))) (define cambia-it-aux (lambda (x y l ac) (cond ((null? l) ac) ((equal? x (car l)) (cambia-it-aux x y (cdr l) (append ac (list y)))) (else (cambia-it-aux x y (cdr l) (append ac (list (car l)))))))) Informática ListasRecursión sobre datos 3.26
Tabla y traza de cambia-it-aux Tabla: l ac (c d a b) () (d a b) (c) (a b) (c d) (b) (c d b) () (c d b b) Traza: > (cambia-it a b (c d a b)) (cambia-it-aux a b (c d a b) ()) (cambia-it-aux a b (d a b) (c)) (cambia-it-aux a b (a b) (c d)) (cambia-it-aux a b (b) (c d b)) (cambia-it-aux a b () (c d b b)) (c d b b) (c d b b) (c d b b) (c d b b) (c d b b) (c d b b) Informática ListasRecursión sobre datos 3.27
Recursión terminal: fib-it La sucesión de Fibonacci: 0,1,1,2,3,5,8,13,... Definición mediante recursión terminal de fib-it: (define fib-it (lambda (n) (if (zero? n) 0 (fib-it-aux n 0 1)))) (define fib-it-aux (lambda (n ac1 ac2) (if (= n 1) ac2 (fib-it-aux ( n 1) ac2 (+ ac1 ac2))))) Informática ListasRecursión sobre datos 3.28
Tabla y traza de fib-it-aux Tabla: n ac1 ac2 5 0 1 4 1 1 3 1 2 2 2 3 1 3 5 Traza: > (fib-it 5) (fib-it-aux 5 0 1) (fib-it-aux 4 1 1) (fib-it-aux 3 1 2) (fib-it-aux 2 2 3) (fib-it-aux 1 3 5) 5 5 5 5 5 5 Informática ListasRecursión sobre datos 3.29
Recursión terminal y recursión profunda: suma-todos-it (suma-todos-it (1 2 3 4)) => 10 (suma-todos-it (1 (2) (3 (4)))) => 10 (suma-todos-it ()) => 0 Definición del procedimiento suma-todos-it: (define suma-todos-it (lambda (lista) (suma-todos-it-aux lista 0))) (define suma-todos-it-aux (lambda (l ac) (cond ((null? l) ac) ((pair? (car l)) (suma-todos-it-aux (append (car l) (cdr l)) ac)) (else (suma-todos-it-aux (cdr l) (+ (car l) ac)))))) Informática ListasRecursión sobre datos 3.30
Tabla de suma-todos-it-aux l (1 (2) (3 (4))) ((2) (3 (4))) (2 (3 (4))) ((3 (4))) ac 0 1 1 3 l (3 (4)) ((4)) (4) () ac 3 6 6 10 Informática ListasRecursión sobre datos 3.31
Bibliografía [Abelson 96] Cap. 1: Building abstractions with procedures. Cap. 1.2: Procedures and processes they generate. [Springer 94] Cap. 2: Procedures and recursion. Cap. 3: Data driven recursion. Informática ListasRecursión sobre datos 3.32