Programación y Estructuras de Datos

Slides:



Advertisements
Presentaciones similares
5. Estructuras no lineales estáticas y dinámicas
Advertisements

ESTRUCTURA DE DATOS Unidad 04 TDA no lineales - Árboles.
IBD Clase 7.
ESTRUCTURA DE DATOS Unidad 04 Árboles BINARIOS.
ESTRUCTURA DE DATOS Unidad 04 Árboles BINARIOS DE BUSQUEDA.
Árboles Grafo que no contiene ciclos, es decir es un grafo también acíclico, pero a su vez es conexo.
ÁRBOLES EN C UNIVERSIDAD “ALONSO DE OJEDA” Facultad de Ingeniería
Unidad 5 Listas Enlazadas Bibliografía: Algoritmos y Estructuras de datos de Aguilar y Martinez. Unidad 9 Autor: Ing Rolando Simon Titiosky.
1 Extensión de un Estructura de Datos Agustín J. González ELO-320: Estructura de Datos y Algoritmos.
ÁRBOLES BINARIOS DE BUSQUEDA
Operaciones sobre un árbol
Árboles binarios. Algoritmos básicos
Tema 4 Árboles. Conceptos Generales..
ESTRUCTURAS DE DATOS AVANZADAS
Algoritmos Aleatorizados
Solución de problemas por búsqueda inteligente
Árboles balanceados AVL
ÁRBOLES DE EXPRESION.
Arboles (Trees) Arboles Arboles binarios Recorridos de árboles
Cont. Arbol Binario de Búsqueda (2). Sobre los recorridos Las versiones recursivas de los recorridos son costosas debido a la gran cantidad de llamadas.
Diplomado en Informática Aplicada
Almacenamiento y Recuperacion de Información TAD_ABB Ana Lilia Laureano Cruces Universidad Autónoma Metroplotiana.
Tema Nº4.
Estructuras dinámicas de datos, TAD Lista, parte 2
Inteligencia Artificial Resolver problemas mediante búsqueda
Listas circulares.
Teoría de Grafos.
Ana Lilia Laureano Cruces UAM-A
Estructura de Datos Lineales
Material de apoyo Unidad 4 Estructura de datos
Árboles.
ÁRBOLES BINARIOS DE BÚSQUEDA
C++ LISTAS C++ 11/04/2017 Ing. Edgar Ruiz Lizama.
Estructuras de Datos MC Beatriz Beltrán Martínez.
Definiciones: conjuntos, grafos, y árboles
Árboles, montículos y grafos Cola de prioridades, montículos
Tópicos I Árboles, montículos y grafos
Ordenamiento, Heapsort y Colas de prioridad
Estructura de Datos En C++
Heaps Mauro Maldonado Abril/2005. Introducción La estructura heap es frecuentemente usada para implementar colas de prioridad. En este tipo de colas,
ESTRUCTURAS DE DATOS I Conocer, comprender y analizar algunos de los principales tipos de estructuras de datos.
ARBOLES ESTRUCTURAS DE DATOS.
Estructura de Datos y Algoritmos
Diseño y análisis de algoritmos
Árboles binarios de búsqueda
Arboles M.C. José Andrés Vázquez FCC/BUAP
ARBOLES ESTRUCTURAS DE DATOS.
Almacenamiento y Recuperacion de Información- Arbol AVL
ÁRBOLES BINARIOS DE BÚSQUEDA BALANCEADOS
Árboles.

Árboles Recomendado: 1. Nivelación Funciones
Árboles Binarios Estructuras de Datos.
Árboles de Búsqueda Binaria
Con el objeto de mejorar el rendimiento en la búsqueda surgen los árboles balanceados. La idea central de estos es la de realizar reacomodó o balanceos.
Listas Ligadas Simples. Definíción I  Es, en sencillas palabras. un grupo de datos organizados secuencialmente, pero a diferencia de los arreglos, la.
Estructura de Datos M.C. José Andrés Vázquez Flores FCC/BUAP
Unidad 6: Árboles.
Estructura de Datos M.C. J. Andrés V. F. FCC/BUAP
1 Árboles de Búsqueda Binaria Agustín J. González ELO-320: Estructura de Datos y Algoritmos.
INSTITUTO TECNOLOGICO DE APIZACO
ARBOLES GENERALIZADOS
Árboles Binarios de Búsqueda (ABB)
A YUDANTÍA 5: A RBOLES Carlos Pulgar R. Mail: Página Ayudantía:
Árboles Binarios * Recorridos * Tipo
Árboles Equilibrados Estructuras de Datos MC Beatriz Beltrán Martínez Primavera 2015.

Matemáticas Discretas MISTI
M.C. Meliza Contreras González
Arboles Binarios: AVL (Adelson – Velskii - Landis)
Transcripción de la presentación:

Programación y Estructuras de Datos Árboles Cursos Propedéuticos 2010 Programación y Estructuras de Datos Dr. René Cumplido, Dra. Claudia Feregrino, M. en C. Juan Manuel Campos y M. en C. Pedro Hernández

Contenido de la sección Introducción Árbol genérico Definición y representación Árboles binarios Definición, implementación, aplicaciones y recorridos Árboles binarios de Búsqueda Definición y principales operaciones (insertar, eliminar, buscar) Árboles AVL (balanceados)

Introducción Hasta ahora, en todas las estructuras existen al menos dos operaciones: Insertar un elemento en el conjunto. Buscar y/o descartar un elemento ¿Que limitaciones existen respecto a la complejidad de sus operaciones básicas?

Introducción Una lista no ordenada tiene: Costo de inserción O(1). Costos de búsqueda O(n). En ambos casos la repetición de n operaciones sobre la estructura da origen a complejidad n2.

Introducción Una lista ordenada en forma ascendente por la prioridad, permite: Seleccionar el mínimo con costo O(1). Insertar manteniendo el orden tiene costo promedio O(n) en el peor caso.

Introducción Estudiaremos usar la estructura de un árbol binario, ya que ésta garantiza que las operaciones de inserción y eliminación sean de complejidad O( log2 (n) )

¿Qué es un árbol? Un árbol es un grafo A que tiene un único nodo llamado raíz que: Tiene 0 relaciones, en cuyo caso se llama nodo hoja. Tiene un número finito de relaciones, en cuyo caso, cada una de esas relaciones es un sub-arbol. Un árbol es una estructura no secuencial.

Ejemplo de un árbol A B C D E F G H I

Nomenclatura básica Todo nodo nj, exceptuando el raíz, está conectado exclusivamente a otro nodo nk donde: nj es el padre de nk (e.g., B es el padre de E) nk es uno de los hijos de nj (e.g., E es un hijo de B) Nodos con el mismo padre son “hermanos” Nodos sin hijos son llamados “hojas” Si existe una trayectoria del nodo nj al nodo nk entonces: nj es antecesor de nk (e.g., A es antecesor de E) nk es descendiente de nj (e.g., E es descendiente de A)

Ejemplo

Más nomenclatura La trayectoria del nodo n1 a nk se define como la secuencia de nodos n1,n2,…,nk, tal que ni es el padre de ni+1. Entonces: La longitud de una trayectoria es el número de ramas recorridas, es decir, K-1. Nivel o profundidad del nodo ni es la longitud de la trayectoria que va del nodo raíz a ni. La altura del nodo ni es longitud de la trayectoria más larga de ni a una hoja.

Implementación Dos formas de implementar: typedef struct { TipoDato dato; struct NodoArbol *hijo1; struct NodoArbol *hijo2; : struct NodoArbol *hijoN; } NodoArbol; struct NodoArbol *hijo; struct NodoArbol *hermano; Dos formas de implementar: Tener un apuntador a cada uno de los hijos. Problema cuando NO sabemos el número de hijos. Mantener los hijos de un nodo en una lista ligada. No hay ninguna restricción sobre número de hijos. Así, un nodo del árbol puede consistir de un dato, un apuntador al primer hijo y un apuntador a la lista de hermanos.

Árboles binarios Un árbol binario en un árbol en el cual cada nodo puede tener como máximo dos hijos. Recursivamente un árbol binario puede definirse como: un árbol vacío, o un nodo raíz con un subárbol izquierdo y un subárbol derecho. Raíz Árbol izquierdo Árbol derecho

Árboles binarios Un árbol binario es una estructura de datos de tipo árbol en donde cada uno de los nodos del árbol puede tener 0, 1, ó 2 subárboles llamados de acuerdo a su caso como: Si el nodo raíz tiene 0 relaciones se llama hoja. Si el nodo raíz tiene 1 relación a la izquierda, el segundo elemento de la relación es el subárbol izquierdo. Si el nodo raíz tiene 1 relación a la derecha, el segundo elemento de la relación es el subárbol derecho. * Si cada nodo que NO es una hoja tiene un subárbol izquierdo y un subárbol derecho, entonces se trata de un árbol binario completo.

Árboles binarios Cuales de las siguientes figuras representa un árbol binario?

Árboles binarios En un primer caso se tiene que el número de nodos n es tres; un nivel (m aristas entre los nodos en una trayectoria desde la raíz a las hojas) y altura h igual dos.

Árboles binarios Con tres niveles: n=15=24-1 m=3 h=4 Con dos niveles: n=7=23-1 m=2 h=3 Con tres niveles: n=15=24-1 m=3 h=4 En un caso general para árboles binarios completos: n = 2h -1, h = m +1 y h=log2 (n+1), despejando h de la primera relación.

Árboles binarios La altura, es el concepto importante para la complejidad, ya que define el número de nodos a revisar en una trayectoria desde la raíz hasta las hojas. Cual es la altura h del árbol anterior?: Si conocemos h, cual es el valor de n?:

Árboles binarios Árboles binarios llenos: Cada nodo del árbol o es una hoja o un nodo interno con exáctamente dos hijos. Árbol binario completo: es aquel en el que todos los nodos tienen dos hijos y todas las hojas están en el mismo nivel. cada nodo,excepto las hojas, tiene el máximo de hijos que puede tener.

Árboles binarios (a) (b) ¿Son completos? ¿Son llenos?

Implementación con arreglos Posición 1 2 3 4 5 6 7 8 9 10 11 Padre -- Hijo Izquierdo Hijo Derecho Hermano Izq Hermano Der

Implementación con apuntadores Los nodos del árbol son estructuras que almacenan los datos, y apuntadores a los subárboles de ese nodo. Estructura del nodo del árbol Representación del Árbol Árbol H D S Y L A

Implementación Cada nodo del árbol consiste en: Un dato (cualquier tipo) Un apuntador al hijo izquierdo Un apuntador al hijo derecho Inicialmente el nodo raíz apunta a NULL. En las hojas del árbol, los apuntadores hacia los hijos izquierdo y derecho son NULL. typedef struct NodoArbol *Arbol; struct NodoArbol { TipoDatol dato; struct NodoArbol *izq; struct NodoArbol *der; };

Operaciones con árboles binarios Con los árboles binarios es posible definir algunas operaciones primitivas, estas operaciones permiten obtener información de un nodo y sirven para desplazarse en el árbol, hacia arriba o hacia abajo.

Operaciones con árboles binarios info(p) que devuelve el contenido del nodo apuntado por p. left(p) devuelve un apuntador al hijo izquierdo del nodo apuntado por p, o bien, devuelve NULL si el nodo apuntado por p es una hoja. right(p) devuelve un apuntador al hijo derecho del nodo apuntado por p, o bien, devuelve NULL si el nodo apuntado por p es una hoja. father(p) devuelve un apuntador al padre del nodo apuntado por p, o bien, devuelve NULL si el nodo apuntado por p es la raíz. brother(p) devuelve un apuntador al hermano del nodo apuntado por p, o bien, devuelve NULL si el nodo apuntado por p no tiene hermano.

Operaciones con árboles binarios Estas otras operaciones son lógicas, tienen que ver con la identidad de cada nodo: isLeft(p) devuelve el valor true si el nodo actual es el hijo izquierdo del nodo apuntado por p, y false en caso contrario. isRight(p) devuelve el valor true si el nodo actual es el hijo derecho del nodo apuntado por p, y false en caso contrario. isBrother(p) devuelve el valor true si el nodo actual es el hermano del nodo apuntado por p, y false en caso contrario.

Operaciones con árboles binarios Como ejemplo, un algoritmo para el procedimiento isLeft: q=father(p); if(q==NULL) return(?????) /* porque p apunta a la raiz */ if (left(q)==???) return(true); return(????);

Operaciones con árboles binarios Como ejemplo, un algoritmo para el procedimiento isLeft: q=father(p); if(q==NULL) return(false) /* porque p apunta a la raiz */ if (left(q)==p) return(true); return(false);

Operaciones con árboles binarios También son útiles las operaciones makeTree, setLeft y setRight. makeTree(x) crea un nuevo árbol binario que consta de un único nodo con un campo de información x y devuelve un apuntador a ese nodo. setLeft(p,x) acepta un apuntador p a un nodo de árbol binario sin hijo izquierdo. Crea un nuevo hijo izquierdo de node(p) con el campo de información x. setRight(p,x) es similar, excepto que crea un hijo derecho.

Aplicaciones de árboles binarios Un árbol binario es una estructura de datos útil cuando se trata de hacer modelos de procesos en donde se requiere tomar decisiones en uno de dos sentidos en cada parte del proceso. Supongamos que tenemos un arreglo en donde queremos encontrar todos los duplicados. Esta situación es bastante útil en el manejo de las bases de datos, para evitar la redundancia.

Aplicaciones de árboles binarios Como encontramos elementos duplicados en un arreglo? Si usamos un árbol binario, el número de comparaciones se reduce bastante, veamos cómo. Como hacemos eso? Una manera de encontrar los elementos duplicados en un arreglo es recorrer todo el arreglo y comparar con cada uno de los elementos del arreglo. Esto implica que si el arreglo tiene n elementos, se deben hacer n comparaciones, claro, no es mucho problema si n es un nu ́mero pequen ̃o, pero el problema se va complicando m ́as a medida que n aumenta.

Aplicaciones de árboles binarios El primer número del arreglo se coloca en la raíz del árbol con sus subárboles izquierdo y derecho vacíos. Luego, cada elemento del arreglo se compara son la información del nodo raíz y se crean los nuevos hijos con el siguiente criterio: Si el elemento del arreglo es igual que la información del nodo raíz, entonces notificar duplicidad. Si el elemento del arreglo es menor que la información del nodo raíz, entonces se crea un hijo izquierdo. Si el elemento del arreglo es mayor que la información del nodo raíz, entonces se crea un hijo derecho.

Aplicaciones de árboles binarios Una vez que ya está creado el árbol, se pueden buscar los elementos repetidos. Si x el elemento buscado, se debe recorrer el árbol del siguiente modo: Sea k la información del nodo actual p. Si x > k entonces cambiar el nodo actual a right(p), en caso contrario, en caso de que x = k informar una ocurrencia duplicada y en caso de que x ≥ k cambiar el nodo actual a left(p).

Recorridos de un árbol Para saber el contenido de todos los nodos en un árbol es necesario recorrer el árbol. Esto es debido a que solo tenemos conocimiento del contenido de la dirección de un nodo a la vez. El proceso de visitar los nodos en algún orden se denomina recorrido. Cualquier recorrido que lista cada nodo del árbol exáctamente una vez se denomina una enumeración de los nodos del árbol.

Recorridos de un árbol ¿cómo lo podemos recorrer?

Recorridos estándar Preorder: Inorder: Postorder: Visitar nodo Visitar árbol izquierdo Visitar árbol derecho Inorder: Postorder: void inorder(NodoArbol *nodo) { if (nodo != NULL) { inorder(nodo->izq); visitar(nodo); inorder(nodo->der); } void postorder(NodoArbol *nodo) { postorder(nodo->izq); postorder(nodo->der);

Ejemplo de recorridos Preorden: A, B, D, E, C, F, G Inorden: D, B, E, A, F, C, G Postorden: D, E, B, F, G, C, A

Árbol binario de búsqueda Es un árbol: Una colección de nodos que puede ser vacía, o que en su defecto consiste de un nodo raíz R y un número finito de estructuras tipo árbol T1,…,Tk, llamados subárboles, los cuales son disjuntos y sus respectivos nodos raíz están conectados a R. Es binario: Cada nodo puede tener como máximo dos hijos, en otras palabras, cada nodo sólo puede tener dos subárboles. Es de búsqueda porque: Los nodos están ordenados de manera conveniente para la búsqueda. Todos los elementos almacenados en el subárbol izquierdo de un nodo con valor K, tienen valores < K. Todos los elementos almacenados en el sub-árbol derecho de un nodo con valor K, tienen valores >= K.

Ejemplos ¿son todos árboles binarios de búsqueda? 2 7 1 8 6 5 4 6 2 8 3 1 4 6 2 8 3 1 4 7

Operación INSERTAR Insertando 5 6 2 8 1 4 3 5 void insertar(NodoArbol *nodo, int elem){ if (nodo == NULL) { nodo=(NodoArbol *)malloc(sizeof(NodoArbol)); nodo->dato = elem; nodo->izq = nodo->der = NULL; } else if (elem < nodo->dato) nodo-izq = insertar(nodo->izq, elem); else if (elem > nodo->dato) nodo->der = insertar(nodo->der, elem); return nodo; 6 2 8 1 4 3 5

Ejercicio Construya el árbol binario de búsqueda, al insertar secuencialmente los valores 5, 9, 3, 7, 8, 12, 6, 4.

Operación BUSCAR 6 2 8 1 4 3 Buscando 4: VERDADERO Buscando 7: FALSO boolean buscar(NodoArbol *nodo, int elem) { if (nodo == NULL) return FALSE; else if (nodo->dato < elem) return buscar(nodo->izq, elem); else if (nodo->dato > elem) return buscar(nodo->der, elem); else return TRUE; } 2 8 1 4 3 Buscando 4: VERDADERO Buscando 7: FALSO

Operación ELIMINAR (1) Existen cuatro distintos escenarios: Intentar eliminar un nodo que no existe. No se hace nada, simplemente se regresa FALSE. Eliminar un nodo hoja. Caso sencillo; se borra el nodo y se actualiza el apuntador del nodo padre a NULL. Eliminar un nodo con un solo hijo. Caso sencillo; el nodo padre del nodo a borrar se convierte en el padre del único nodo hijo. Eliminar un nodo con dos hijos. Caso complejo, es necesario mover más de un apuntador.

ELIMINAR (casos sencillos) Eliminar nodo hoja Eliminar 3 Eliminar nodo con un hijo Eliminar 4 6 2 8 3 1 4 6 2 8 1 4 3

ELIMINAR (Caso complejo) Eliminar nodo con dos hijos Eliminar 2 6 6 2 8 3 8 1 4 1 4 copiar valor 3 5 3 5 eliminar 1. Remplazar el dato del nodo que se desea eliminar con el dato del nodo más pequeño del subárbol derecho 2.Eliminar el nodo más pequeño del subárbol derecho (caso fácil)

Otro ejemplo (caso complejo) Eliminar nodo con dos hijos Eliminar 2 6 6 3 8 1 4 5 3.5 1 2 8 1 4 3 5 Eliminar 3. Eliminación de un nodo con un hijo. 2 3.5

Ejercicio Dibujar el árbol resultante después de aplicar las siguientes eliminaciones de 20, 27, 14 y 22 al siguiente árbol.

Implementación ELIMINAR else /* encontramos el elemento */ /* tiene dos hijos */ if (nodo->izq && nodo->derecho){ aux = enontrar_min(nodo->der); nodo->dato = aux->dato; nodo->der = eliminar( nodo->der; nodo->dato); } /* un solo hijo */ else { aux = nodo; if (nodo->izq == NULL) hijo = nodo->der; if (nodo->der == NULL) hijo = nodo->izq; free(aux); return hijo; return nodo; void eliminar(NodoArbol *nodo, int elem) { NodoArbol *aux, * hijo; if (nodo == NULL) return; /* no existe nodo */ /* recorrer árbol hasta encontrar elem */ else if (elem < nodo->dato) nodo-izq = eliminar(nodo->izq, elem); else if (elem > nodo->dato) nodo->der = eliminar(nodo->der, elem);

Árboles desbalanceados La figura muestra un árbol binario de búsqueda, sin embargo éste NO facilita la búsqueda de elementos. El problema es que está muy desbalanceado. La solución es balancearlo, y con ello asegurar que el tiempo promedio de búsqueda sea de O(log2N) (menor que la búsqueda lineal). 2 7 1 8 6 5 4

Árboles AVL Propuestos por Adelson-Velskii and Landis. Árboles binarios con una condición de balance. Esta condición es usada para asegurar que en todo momento la altura del árbol es O(log2N) (N = número de nodos). Condición de balance: para cada nodo del árbol, las alturas de sus subárboles izquierdo y derecho sólo pueden diferir como máximo en 1. La condición de balance debe mantenerse después de cada operación de inserción o eliminación.

¿son árboles AVL? Altura subárbol izq. Altura subárbol der. 0,0 1,0 1,2 3,2 0,0 1,1 1,2 3,1 6 2 8 3 1 4 7 5 6 2 8 3 1 4

Construcción de un árbol AVL Cuando se inserta un nodo se modifican las condiciones de balance en la trayectoria hacia la raíz. Si se presenta una desbalance, entonces es necesario hacer algunas modificaciones al árbol. Dos tipos de modificaciones: Rotación simple Rotación doble 3,1 6 2 8 1 4 5

Rotación simple X K1 K2 Y Z X K1 K2 Y Z Z K1 K2 Y X K2 K1 Y Z X

Ejemplo rotación simple 2 1 4 3 6 5 4 2 5 6 1 3

NO siempre es suficiente 6 2 8 3 1 4 2 1 6 3 4 8

Rotación doble D A B C D A B C A D B C D A B C K1 K3 K2 K1 K3 K2 K1 K3

Ejemplo doble rotación 4 2 7 1 3 6 4 14 5 15 13 k3 2 6 k1 1 3 5 14 k2 7 15 13

Ejercicio Construya un árbol binario AVL, insertando los valores 1, 2, …, 10 secuencialmente. 5 2 7 1 4 6 9 8 10 3