Tema 6: Estructuras de datos recursivas

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

Tema Árboles generales. 9.2 Árboles binarios 9.3 Árboles de búsqueda

Árboles. Un grafo no dirigido es un árbol si y sólo si existe una ruta unica simple entre cualquiera dos de sus vértices.

Tema 3: Recursión. Índice

Tema 5: Abstracción. Índice

Algoritmos y programas. Algoritmos y Estructuras de Datos I

APUNTADORES. Un apuntador es un objeto que apunta a otro objeto. Es decir, una variable cuyo valor es la dirección de memoria de otra variable.

GUÍA BÁSICA DE SCHEME v.4

Tema 3.- Predicados y sentencias condicionales

Estructuras de datos. Estructuras de datos

Definición 1.1 Sea G = (V, A) un grafo no dirigido. G se denomina árbol si es conexo y no contiene ciclos.

Tecnólogo Informático- Estructuras de Datos y Algoritmos- 2009

Clase 1 de prácticas: Introducción a Scheme

Tema 8: Construcción de tipos de datos

Unidad Nº V Listas Enlazadas

GRAMATICAS LIBRES DEL CONTEXTO

Retículos y Álgebras de Boole

(d) Puede haber estrategias que funcionan mejor que Minimax si el contrincante es

Definición 1 Un semigrupo es un conjunto E provisto de una operación binaria asociativa sobre E, se denota por (E, ).

Algoritmos y estructuras de datos

ELO320 Estructuras de Datos y Algoritmos. Arboles Binarios. Tomás Arredondo Vidal

(e) Con la poda alfa-beta se eliminan nodos que nunca serán alcanzados

Isabelle como un lenguaje funcional

Formulación del problema de la ruta más corta en programación lineal

Clases e instancias. Algoritmos y Estructuras de Datos I. Clases e instancias. memoria dinámica.

DEFINICION. Ing. M.Sc. Fulbia Torres Asignatura: Estructuras de Datos Barquisimeto 2006

Tema: Los Grafos y su importancia para la optimización de redes.

Guía práctica de estudio 05: Diagramas de flujo

Ecuaciones de primer ysegundo grado

Árboles. Cursos Propedéuticos Dr. René Cumplido M. en C. Luis Rodríguez Flores

Para poder comenzar a trabajar con Excel, es necesario considerar los siguientes términos:

Conceptos a tratar. Fundamentos de la Programación Orientada a Objetos Ampliación sobre clases y objetos

UNIDAD 9. DATOS COMPLEJOS PILAS

Binary Decision Diagrams

PROBLEMA DE PROGRAMACIÓN LINEAL RESUELTO POR MÉTODO SIMPLEX

TEMA 8. GEOMETRÍA ANALÍTICA.

Programación orientada a objetos. Capítulo 8 Mejora de las estructuras mediante herencia

Capítulo 4. Lógica matemática. Continuar

Bases Matemáticas para la Educación Primaria. Guía de Estudio. Tema 3: Números racionales. Parte I: Fracciones y razones Números racionales

funciones printf scanf

Profesorado de Informática Ciencias de la Computación INET- DFPD Matemática I - Matemática Discreta usando el computador Ing. Prof.

Tema 13: Apuntadores en C

(CR) Prof. Manuel López Mateos Curso de Cálculo I,

Apuntes de Regulación y Automatización. Prácticas y Problemas.

MICROSOFT EXCEL 2010

Construcción de tablas de análisis sintáctico LL(1)

Universidad de Valladolid. Departamento de informática. Campus de Segovia. Estructura de datos Tema 4: Ordenación. Prof. Montserrat Serrano Montero

CLASES QUE UTILIZAN OBJETOS. RELACIÓN DE USO ENTRE CLASES JAVA. CONCEPTO DE DIAGRAMA DE CLASES. (CU00641B)

Ejercicios de Lógica Proposicional *

Tema 2. Fundamentos de la Teoría de Lenguajes Formales

Procesadores de Lenguaje

Propedéutico de Programación

MAXIMOS Y MINIMOS RELATIVOS

Derivadas Parciales (parte 2)

Tema 4: Procedimientos y estructuras recursivas

Sobre funciones reales de variable real. Composición de funciones. Función inversa

MODELOS DE COMPUTACION I Preguntas Tipo Test. 1. El lema de bombeo puede usarse para demostrar que un lenguaje determinado es regular.

ESTRUCTURA Y TECNOLOGÍA DE LOS COMPUTADORES I. TEMA 4 Algebra booleana y puertas lógicas

Redes Semánticas. IIMAS Inteligencia Artificial. Alumno: Vicente Iván Sánchez Carmona Profesora: Dr. Ana Lilia Laureano

INTERVALOS Y SEMIRRECTAS.

ESTADÍSTICA CON EXCEL

BASES DE DATOS TEMA 2 MODELOS DE DATOS

Estructuras Secuenciales. Funciones de Control. Junio 2007

Si salgo temprano hoy, me voy al cine.

EL PAQUETE JAVA.UTIL DEL API JAVA. PRINCIPALES INTERFACES Y CLASES: STRINGTOKENIZER, DATE, CALENDAR, HASHSET, TREEMAP, TREESET...

Una ecuación puede tener ninguna, una o varias soluciones. Por ejemplo: 5x 9 = 1 es una ecuación con una incógnita con una solución, x = 2

Algoritmos de Ordenación

Técnicas de inteligencia artificial. Visión Artificial Visión 3D

Manejo de Bases de Datos Mysql en Lenguaje C

Tema 9. Algoritmos sobre listas. Programación Programación - Tema 9: Algoritmos sobre listas

Espacios Vectoriales. AMD Grado en Ingeniería Informática. AMD Grado en Ingeniería Informática (UM) Espacios Vectoriales 1 / 21

En cualquier caso, tampoco es demasiado importante el significado de la "B", si es que lo tiene, lo interesante realmente es el algoritmo.

UNIVERSIDAD MAYOR DE SAN SIMÓN FACULTAD DE CIENCIAS Y TECNOLOGÍA INGENIERÍA DE SISTEMAS BÚSQUEDA PRIMERO EL MEJOR

Tablas Hash y árboles binarios

Manejo de módulos y recursión en programación. Pseudocódigo. (CU00204A)

Tema: Clases y Objetos en C#. Parte II.

CURSO 2013/2014 RESUMEN LÍMITES Y CONTINUIDAD 2, ,61 2,01 4,0401 1,99 3,9601 2,001 4, ,999 3,

Métodos para escribir algoritmos: Diagramas de Flujo y pseudocódigo

Complejidad computacional (Análisis de Algoritmos)

ƒ : {(1, 4), (2, 5), (3, 6), (4, 7)}.

Herramientas para investigadoras e investigadores sociales

Qué son las fórmulas de Excel?

Estructuras de datos: Árboles binarios de

El Juego como Problema de Búsqueda

324 MR Versión 1 Prueba Integral 1/3 Semana 10 Lapso

CONTINUIDAD DE FUNCIONES. SECCIONES A. Definición de función continua. B. Propiedades de las funciones continuas. C. Ejercicios propuestos.

PROCESADORES DE LENGUAJE EXAMEN FINAL 8-JUNIO-07

Uso de formateador. Procedimiento:

Objetivos formativos de Matemática Discreta. Tema 1: Conjuntos, aplicaciones y relaciones

1. DML. Las consultas multitabla

Árboles AVL. Laboratorio de Programación II

Derivadas 6 ACTIVIDADES. 1. Página 140. Función f(x) x 2 1: Función g(x) x 3 7: 2. Página Página Página

ANEXO XVII DE LA RESOLUCION N

Procesadores de lenguaje Tema 6 La tabla de símbolos

Estructuras de datos Árboles B

Tema 5. Estructura de datos Pila

Árboles binarios de búsqueda ( BST )

MatemáticaDiscreta&Lógica 1

T0. TRANSFORMADAS DE LAPLACE

Tema 6. Gestión dinámica de memoria

Transcripción:

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 y pueden contener otras listas. Una lista jerárquica es una lista cuyos elementos son datos atómicos u otras listas jerárquicas. Por ejemplo, supongamos la siguiente lista: ((1 2 3) 4 5) Esta lista define la siguiente estructura jerárquica de dos niveles: * / \ * 4 5 / \ 1 2 3 En este tipo de jerarquía cada lista define un nodo que representa un nuevo nivel en la jerarquía. Los datos de la estructura definen los elementos finales de la jerarquía y los llamamos hojas. Como sabes, los árboles son el tipo de datos típico que se usa en computación para representar estructuras jerárquicas. Qué diferencia fundamental hay entre los árboles y las listas jerárquicas? En un árbol todos los nodos tienen un dato asociado, mientras que en las listas jerárquicas los datos sólo se encuentran en las hojas. Por esta razón, los árboles definidos por estas listas no son verdaderos y los llamaremos pseudo árboles. La utilidad principal de las listas jerárquicas es doble. Por una parte definen una estructura relativamente sencilla en la que podemos definir y probar un conjunto de funciones que después van a ser directamente adaptables a los árboles. Por otra parte, representan una estructura de datos muy flexible con la que representar gran cantidad de objetos. En los nombres de las funciones definidas para listas jerárquicas usaremos el sufijo pt (pseudo tree) para no confundirlas con las funciones que definiremos más adelante para árboles verdaderos. Por ejemplo, la función levels-pt contará el número de niveles de un pseudo árbol o lista jerárquica, mientras que la función levels-tree contará el número de niveles de un árbol genérico. (leaf? dato): indica si un dato de una lista jerárquica es una hoja o no (count-leaves-pt lista): devuelve el número de elementos atómicos de la estructura lista (levels-pt lista): cuenta el número de niveles que contiene la lista jerárquica lista (member-pt? dato lista): indica si el dato es un dato atómico que pertenece a la lista jerárquica lista (map-pt f lista): devuelve una nueva lista jerárquica con la misma estructura que lista con los datos resultantes de aplicar f a los datos originales de lista Page 2

A continuación comentamos la implementación de cada una de estas funciones. La función leaf? nos dice si un nodo es una hoja. No tenemos más que comprobar si se trata de una pareja o un dato atómico. (define (leaf? x) (not (pair? x))) La función count-leaves-pt recorre todos los niveles de la lista jerárquica y devuelve el número de elementos atómicos que contiene. Utilizando la terminología de árboles, devuelve el número de hojas del pseudo árbol que se le pasa como argumento. (define (count-leaves-pt x) (cond ((null? x) 0) ((leaf? x) 1) (else (+ (count-leaves-pt (car x)) (count-leaves-pt (cdr x)))))) La función levels-pt devuelve el número de nives de la lista que se le pasa como argumento. Para su implementación, realiza una llamada recursiva con el primer dato de la lista y el resto de la lista, por lo que el argumento x puede ser un dato o un lista. (define (levels-pt x) (cond ((null? x) 0) ((leaf? x) 0) (else (max (+ 1 (levels-pt (car x))) (levels-pt (cdr x)))))) La función member-pt? recorre el pseudo árbol y comprueba si alguno de sus datos coincide con el argumento que le pasamos. La implementación realiza un recorrido del pseudo árbol llamando de forma recursiva a la propia función con el primer elemento de la lista (que puede ser, a su vez, otra lista jerárquica) y con el resto de la lista. (define (member-pt? x lista) (cond ((null? lista) #f) ((leaf? lista) (= x lista)) (else (or (member-pt? x (car lista)) (member-pt? x (cdr lista)))))) La función square-pt construye una nueva lista jerárquica con los elementos de la que se le pasa como parámetro elevados al cuadrado. Llama a la función cons para montar la nueva lista con el resultado que devuelve las llamadas recursivas. (define (square-pt lista) Page 3

(cond ((null? lista) '()) ((leaf? lista) (square lista)) (else (cons (square-pt (car lista)) (square-pt (cdr lista)) )) )) La función map-pt generaliza la función anterior, ya que permite pasar como argumento la función que se aplica a los datos de la lista. (define (map-pt f lista) (cond ((null? lista) '()) ((leaf? lista) (f lista)) (else (cons (map-pt f (car lista)) (map-pt f (cdr lista)) )) )) Un ejemplo de uso de listas jerárquicas es el propio Scheme. Las expresiones de Scheme son listas jerárquicas. Por ejemplo, la expresión (let ((x 12) (y 5)) (+ x y))) representa la siguiente estructura jerárquica 2. Árboles binarios Un árbol binario es una estructura que contiene tres elementos: un dato, un árbol binario izquierdo y un árbol binario derecho. Esta definición es recursiva y necesita un caso base. Es el siguiente: un árbol binario puede ser también un árbol-vacío, un símbolo especial (usaremos la lista vacía) que simboliza un árbol que no tiene datos ni hijos. En nuestra implementación la estructura en la que se guarda los elementos del árbol es una lista de tres elementos. Page 4

Llamamos raíz al nodo inicial del árbol y rama izquierda y rama derecha a los árboles izquierdos y derechos. Las funciones que definen la barrera de abstracción del tipo de datos son las siguientes. Constructores: (make-btree dato izq der): construye un árbol binario a partir de un dato y otros dos árboles binarios empty-btree: define el árbol binario vacío Selectores: (empty-btree? btree): comprueba si un árbol binario es vacío (datum-btree btree): devuelve el dato de la raíz del árbol y provoca un error si el árbol está vacio (left-btree btree): devuelve el hijo izquierdo de la raíz del árbol y provoca un error si está vacío (right-btree btree): devuelve el hijo derecho de la raíz del árbol y provoca un error si está vacío (empty-btree? btree): comprueba si un árbol binario está vacío La implementación en Scheme de estas funciones es como se muestra a continuacion. (define (make-btree dato izq der) (list dato izq der)) (define empty-btree '()) (define empty-btree? null?) (define (datum-btree btree) (car btree)) (define (left-btree btree) (car (cdr btree))) (define (right-btree btree) (car (cdr (cdr btree)))) Supongamos el siguiente árbol binario, que representa una expresión matemática. * / \ + 8 / \ 5 3 El siguiente código muestra cómo se construye este árbol binario con los constructores que hemos definido. (define t1 (make-btree 5 empty-btree empty-btree)) (define t2 (make-btree 3 empty-btree empty-btree)) (define t3 (make-btree '+ t1 t2)) (define t4 (make-btree 8 empty-btree empty-btree)) (define t5 (make-btree '* t3 t4)) Page 5

Veamos ahora algunas operaciones sobre árboles binarios. La función btree-to-list construye una lista con los elementos contenidos en un árbol binario. (define (btree-to-list btree) (if (null? btree) '() (append (btree-to-list (hijo-izq btree)) (list (dato btree)) (btree-to-list (hijo-der btree))))) La recursión de esta función se basa en obtener el dato de la raíz, obtener la lista de elementos de la rama izquierda (confía en la recursión, recuerdas?) y la lista de elementos de la rama derecha. La función append concatena todos los elementos. Dependiendo del orden en que los concatenemos aparecerán los elementos en pre-order, in-order o post-order. La función insert-btree realiza una inserción de un dato en un árbol binario ordenado. El hecho de que el árbol es ordenado implica que todos los datos del hijo izquierdo son menores que el dato de la raíz y los del hijo derecho son mayores. Por eso la recursión de la función se basa en identificar en qué subárbol va el dato que estamos insertando. Si el dato es mayor que la raíz hay que ponerlo en el hijo derecho, por lo que construimos un nuevo árbol con la misma raíz e hijo izquierdo que el actual y como hijo derecho ponemos el resultado de la llamada recursiva de insertar un dato en el árbol derecho ( confía en la recursión!). Si el dato es menor hacemos lo contrario. (define (insert-btree x btree) (cond ((null? btree) (make-btree x nil nil)) ((< x (dato btree)) (make-btree (dato btree) (insert-btree x (hijo-izq btree)) (hijo-der btree))) ((> x (dato btree)) (make-btree (dato btree) (hijo-izq btree) (insert-btree x (hijo-der btree)))) (else btree))) Es muy importante notar que en programación funcional no es posible modificar las estructuras de datos porque no existe el concepto de estado de la computacion. Por eso, las funciones siempre devuelven estructuras nuevas, creadas a partir de los parámetros de entrada. Esto tiene sus ventajas e inconvenientes. Entre las ventajas se encuentra la sencillez, mantenibilidad, reusabilidad y robustez del enfoque debido a la no existencia de efectos laterales en las funciones. En la computación Page 6

procedural, donde existen estructuras de datos que pueden ser modificadas por distintos procedimientos, hay que tener mucho cuidado los efectos laterales provocados por que una función modifica una estructura en la que se basa otra función. Entre los inconvenientes se encuentra el coste temporal de la operación. Al no existir la posibilidad de modificar sólo una parte de la estructura se obliga a copiar todos sus datos en una estructura nueva recién creada. Esto impone un coste mínimo de O(n). La función insert-list-btree se basa en la función anterior para insertar todos los elementos de una lista en un árbol binario. Al igual que en el caso anterior, hay que hacer notar que no existe tal inserción, sino que se construye un árbol nuevo que se devuelve como resultado. (define (insert-list-btree list btree) (if (null? list) btree (insert-list-btree (cdr list) (insert-btree (car list) btree)))) La función list-to-btree se podría considerar un constructor de árboles binarios orddenados a partir de una lista. Está basado en las funciones anteriores. Otro posible nombre para esta función sería make-btree-from-list. (define (list-to-btree list) (if (null? list) list (insert-list-btree (cdr list) (make-btree (car list) empty-btree empty-btree)))) La función member-btree? comprueba si un dato pertenece a un árbol binario ordenado. Está basada en la típica búsqueda binaria con coste log(n). (define (member-btree? x btree) (cond ((null? btree) #f) ((= x (dato btree)) #t) ((< x (dato btree)) (member-btree? x (hijo-izq btree))) (else (member-btree? x (hijo-der btree))))) 3. Árboles genéricos Los nodos de los árboles genéricos pueden tener un número variable de hijos, a diferencia de Page 7

los nodos de los árboles binarios que sólo pueden tener dos hijos como máximo. Se usan en un gran número de dominios en los que es necesario representar estructuras jerárquicas: procesadores de lenguaje, documentos XML, documentos HTML, etc. Definición del tipo de datos árbol: Un árbol genérico está formado a partir de un nodo raíz que contiene un dato y una lista de hijos que, a su vez, son árboles genéricos. La lista de hijos puede ser vacía. A diferencia de los árboles binarios, en los árboles genéricos no usamos el concepto de árbol-vacío. Un árbol o nodo hoja es un árbol cuya lista de hijos es una lista vacía. En Scheme es muy fácil implementar un árbol genérico, construyendo una lista cuyo primer elemento es el dato del nodo y cuyo resto de elementos (cdr) son los hijos. Constructores: (define (make-tree dato hijos) Selectores: (cons dato hijos)) (define (datum-tree tree) (car tree)) (define (children-tree tree) (cdr tree)) Ejemplo de uso: (define t1 (make-tree 4 '())) (define t2 (make-tree 5 '())) (define t3 (make-tree 3 '())) (define t4 (make-tree '* (list t1 t2 t3))) (define tree (make-tree '+ (list t3 t4))) Un árbol binario usando esta implementación: (define t1 (make-tree 9 '())) (define t2 (make-tree 32 '())) (define t3 (make-tree 52 '())) (define t4 (make-tree 102 '())) (define t5 (make-tree 28 (list t1 t2))) (define t6 (make-tree 70 (list t3 t4))) (define tree (make-tree 40 (list t5 t6))) Algunas operaciones sobre árboles genéricos. La función square-tree devuelve el árbol resultante a aplicar la función square a los números del árbol que se pasa como parámetro. Es importante notar, al igual que hacíamos cuando hablábamos de árboles binarios, que el árbol resultante es una copia del árbol que se pasa como parámetro y que no se pueden modificar directamente los datos del árbol original porque nos encontramos en el Page 8

paradigma de programación funcional. (define (square-tree tree) (make-tree (square (dato tree)) (map square-tree (children-tree tree)) )) La implementación es bastante interesante. La recursión se basa en aplicar la propia función a cada uno de los hijos. Para ello se obtiene la lista de hijos con la función children-tree y se usa la función map para aplicar la propia función a todos los elementos de esa lista (que son árboles). La lista de árboles resultante se utiliza para construir el árbol que se devuelve añadiendo como dato el cuadrado del dato original. La función tree-to-list devuelve una lista con todos los elementos del árbol. (define (tree-to-list tree) (if (null? (children-tree tree)) (list (datum-tree tree)) (cons (datum-tree tree) (forest-to-list (children-tree tree))))) (define (forest-to-list forest) (if (null? forest) forest (append (tree-to-list (car forest)) (forest-to-list (cdr forest))))) La recursión de esta función es muy interesante, ya que se basa en una recursión mútua. La función tree-to-list obtiene la lista de hijos del nodo actual. A esta lista de árboles la llamamos forest (bosque). Se hace entonces una llamada a una función forest-to-list que devolverá una lista con todos los datos que haya en todos los árboles hijos. A su vez, esta función forest-to-list es una función recursiva que toma una lista de árboles y va construyendo una lista de datos a base de llamadas a la función tree-to-list para cada árbol de la lista. Por último, la función map-tree es la generalización de la función square-tree y permite aplicar una función cualquiera de un argumento a todos los datos del árbol inicial, devolviendo el árbol resultante. (define (map-tree f tree) (make-tree (f (datum-tree tree)) (map-forest f (children-tree tree)))) (define (map-forest f forest) (if (null? forest) forest (cons (map-tree f (car forest)) (map-forest f (cdr forest))))) La implementación de esta función tiene un patrón similar a tree-to-list. Page 9

4. Referencias Para saber más de los temas que hemos tratado en esta clase puedes consultar las siguientes referencias: Structure and Interpretation of Computer Programs (http://mitpress.mit.edu/sicp/full-text/book/book.html), Abelson y Sussman, MIT Press 1996 (capítulos 2.2.2 y 2.3.3). Disponible biblioteca politécnica (acceso al catálogo (http://gaudi.ua.es/uhtbin/boletin/285815) ) Page 10