Estructura de Datos Árboles Binarios de Búsqueda ABB Prof.: Mauricio Solar Prof.: Lorna Figueroa Primer Semestre, 20 1 Arboles de Búsqueda Binaria El árbol binario de búsqueda (ABB) toma su nombre del método de búsqueda dicotómico usado para listas ordenadas, usa un array para mantener un conjunto de items (número de items limitado, y operaciones de inserción y borrado de elementos costosas). Una implementación dinámica sería muy ineficiente. Otra solución consistiría en utilizar un árbol para mantener la información ordenada, con operaciones de inserción y extracción muy eficientes. 2 Arboles de Búsqueda Binaria El TAD ABB es un árbol binario en el que los nodos están ordenados. El orden impuesto a los nodos es tal que para cada nodo, todos los valores de su subárbol izquierdo son menores que su valor, y todos los valores del derecho son mayores. El tipo base requiere una relación de orden total. Un árbol ordenado lleno permite la búsqueda óptima de sus elementos. 3
Arboles de Búsqueda Binaria En un árbol binario ordenado cada vez que se compara el elemento buscado con la raíz se decide si continuar hacia abajo por la derecha o por la izquierda, dejando así la mitad de los nodos a un lado. En un número de comparaciones proporcional a la altura del árbol (h log 2 (N)) se habrá decidido si el elemento está o no en el árbol. Por ejemplo, si hay 32.68 (= 2 ) elementos en el árbol de búsqueda lleno, sólo se requieren comparaciones. 4 Arboles de Búsqueda Binaria Los árboles binarios de búsqueda son estructuras de datos con un gran rendimiento cuando las tareas a realizar implican búsquedas, inserciones y eliminación de nodos. No basta con almacenar la información en un árbol para facilitar la búsqueda, se debe utilizar un tipo especial de árbol: un árbol binario de búsqueda. Si además se quiere que la búsqueda sea eficiente se deben utilizar árboles de búsqueda binarios equilibrados. Árboles de Búsqueda Binaria 3 21 30 24 6
ABB - Definición Un árbol binario de búsqueda es una estructura de datos en el que para todos sus nodos, el hijo izquierdo, si existe, contiene un valor menor que el nodo padre y el hijo derecho, si existe, contiene un valor mayor que el del nodo padre. 3 21 30 24 ABB - Definición Se define ABB para un conjunto S, como un árbol binario rotulado, en que cada nodo v tiene un rótulo l(v) tal que : Para todo u en el subárbol derecho de v, l(u) > l(v) Para todo u en el subárbol izquierdo de v, l(u) < l(v) Para a S, existe un único v tal que l(v) = a 8 El TAD ABB Son una subclase muy importante del TAD AB ya que permiten el ordenamiento y búsqueda de datos en forma simple y eficiente. La especificación del TAD ABB es muy similar a la de AB.
El TAD ArbolBB Operaciones: CrearArbol ArbolBB Su resultado es la creación de un ABB vacío. ArbolVacio(ArbolBB) Logico Devuelve cierto si el argumento de entrada es un ABB vacío, falso en caso contrario. BuscarNodo(ArbolBB, TElemento x) ArbolBB A partir de un ABB y de un valor de tipo base, el resultado es el ABB cuyo nodo raíz contiene dicho valor. El TAD ArbolBB InsertarNodo(ArbolBB, TElemento x) ArbolBB A partir de un ABB y de un valor de tipo base, el resultado es un nuevo ABB en el que se ha añadido el nuevo valor (es decir, la inserción es ordenada). EliminarNodo(ArbolBB, TElemento x) ArbolBB A partir de un ABB y de un valor de tipo base, el resultado es un nuevo ABB en el que se ha eliminado el nodo que contenía la información de tipo base. Existen tres casos posibles: a) Que el nodo sea una hoja b) Que el nodo a eliminar tenga sólo un hijo c) Que el nodo a eliminar sea un nodo interior 11 ABB Ejemplo Para la secuencia:,, 14,,,,, se construye el ABB: 14 InOrden :,,,, 14,,
El TAD ABB Ejemplo Debido al orden impuesto sobre los elementos de un ABB no vacío el menor de ellos es aquel que está almacenado en el nodo más a la izquierda del mismo. ArbolBB Minimo (AB ab) { /* /* pre: ab abes es un un ABB no no vacío post: retorna el el mínimo elemento de de ab ab */ */ if if (ArbolVacio(SubArbIzq(ab))) return RaizAB(ab); else return Minimo(SubArbIzq(ab)); } 13 ABB BuscarNodo Suponga que se busca un elemento x en el árbol. Lo primero es comprobar si se encuentra en el nodo raíz. Si no es así, si el elemento buscado es menor que el contenido en el nodo raíz se deduce que, de estar en el árbol, se encuentra en el subárbol izquierdo. Si el elemento buscado es mayor que el contenido en el nodo raíz se deduce que, de estar en el árbol, se encuentra en el subárbol derecho. Para continuar la búsqueda en el subárbol adecuado se aplica recursivamente el mismo razonamiento. 14 ABB BuscarNodo El esquema del algoritmo será el siguiente : 1. Si el valor del nodo actual es igual al valor buscado encontrado. 2. Si valor buscado es menor que el del nodo actual buscar en el subárbol izquierdo. 1. Si valor buscado es mayor que el del nodo actual buscar en el subárbol derecho. 1. Si el valor no está en el árbol no encontrado.
ABB BuscarNodo Implementación typedef int TipoElemento; typedef struct nodo { TipoElemento dato; struct nodo *izq; struct nodo *der; } Nodo; typedef Nodo* ArbolBinar; Autor: Ing Rolando Simon Titiosky 16 ABB BuscarNodo Implementación Nodo *BuscarNodo(Nodo *raiz, TipoElemento buscado) { if(!raiz) return 0; 0; /*Árbol vacío*/ else if if (buscado == raiz >dato) return raiz; else if if (buscado < raiz >dato) return BuscarNodo(raiz >izq, buscado); else return BuscarNodo(raiz >der, buscado); } Autor: Ing Rolando Simon Titiosky 1 ABB BuscarNodo Implementación 2 tab* BuscarNodo2 (tab *A; *A; telemento x) x) { tab p = A; A; BOOLEAN enc; enc enc = false; while ((((!! enc) && (( p!= p!= NULL )))) { enc enc = p -> -> info == == x; x; if if!! enc enc if if (x (x < p -> -> info )) p = SubArbolIzq(p); else p = SubArbolDer(p); } Si el resultado devuelto es NULL, significa return p; p; que no se ha encontrado el elemento buscado }
ABB InsertarNodo La inserción de un elemento está basado en el algoritmo de búsqueda. Se determina si el elemento está en el árbol, Si está, no se inserta. En caso contrario, se agrega como hoja. 1 ABB InsertarNodo Ciclo: mientras no sea un árbol vacío o hasta que se encuentre el elemento. Si el valor del nodo raíz es mayor que el elemento buscado, continuar la búsqueda en el árbol izquierdo: Padre = nodo nodo = nodo -> izq Si el valor del nodo raíz es menor que el elemento buscado, continuar la búsqueda en el árbol derecho: Padre = nodo nodo = nodo -> der 20 Para cada secuencia, construir el ABB correspondiente y determinar recorrido en: InOrden Postorden PreOrden 14 4 21
Para : 14 Arbol vacío NULL 22 Para : 14 Arbol vacío Insertar : NULL 23 Para : 14 Arbol vacío Insertar : Insertar : NULL 24
Para : 14 Arbol vacío Insertar : Insertar : Insertar : NULL 2 Para : 14 Insertar 14: 14 26 Para : 14 Insertar 14: Insertar : 14 14
Para : 14 Insertar 14: Insertar : Insertar : 14 14 14 28 Para : 14 Insertar : 14 InOrden: 14-2 Entrada: 4 Arbol vacío NULL 30
Entrada: 4 Arbol vacío NULL Insertar : 31 Entrada: 4 Arbol vacío NULL Insertar : Insertar : 32 Entrada: 4 Arbol vacío Insertar : Insertar : Insertar 4: NULL 4 33
Para: 4 Insertar : 4 34 Para: 4 Insertar : Insertar : 4 4 3 Para: 4 Insertar : Insertar : Insertar : 4 4 4
Para: 4 Insertar : 4 InOrden: 4 3 ABB InsertarNodo Implementación Es Es una una extensión de de la la operación de de Búsqueda Si Si el el árbol está vacío se se inserta directamente SINO: Buscará en en el el árbol el el lugar correcto de de Inserción void InsertarNodo (Nodo** raiz, TipoElemento dato) { if if (!(*raiz)) *raiz = CrearNodo(dato); else if if (dato < (*raiz) >dato) InsertarNodo(&((*raiz) >izdo), dato); else InsertarNodo(&((*raiz) >dcho), dato); } Autor: Ing Rolando Simon Titiosky 38 ABB InsertarNodo Implementación 2 void InsertarNodo_2 (tab **A; telemento x) x) { if if (*A == == NULL )){ *A *A = (tab *) *) malloc(sizeof(tab)); (*A )->info = x; x; (*A )->izq = NULL; (*A )->der = NULL; } else if( if( (*A) -> -> info > x) x) InsertarNodo(&(*A) -> -> izq, izq, x); x); else if( if( (*A) -> -> info < x) x) InsertarNodo(&(*A) -> -> der, x); x); else printf( Dato repetido ); ); } 3
ABB EliminarNodo 1. Buscar el nodo que se desea borrar. 2. Si se encuentra el nodo hay que contemplar tres casos posibles: a) Si el nodo a borrar no tiene hijos se libera el espacio que ocupa. b) Si el nodo a borrar tiene un hijo este hijo ocupa la posición ocupada por el nodo borrar. c) Si el nodo a borrar tiene dos hijos i. Se busca el máximo de la rama izquierda, o el mínimo de la rama derecha. ii. Se sustituye el nodo a borrar por el nodo encontrado (máximo o mínimo). iii. Se elimina el nodo copiado (máximo o mínimo). 40 El TAD ABB EliminarNodo a) Que el nodo sea una hoja: 41 El TAD ABB EliminarNodo b) Que el nodo tenga un hijo: 42
El TAD ABB EliminarNodo c) Que el nodo sea interno: 43 ABB EliminarNodo; caso a) Si el nodo a borrar no tiene hijos se libera el espacio que ocupa. Árbol Inicial: Árbol Final: 21 21 24 Suprimir 24 44 ABB EliminarNodo; caso b) Si el nodo a borrar tiene un hijo este hijo ocupa la posición ocupada por el nodo borrar. Árbol Inicial: Árbol Final: 21 Suprimir 21 4
ABB EliminarNodo; caso c) Si el nodo a borrar tiene dos hijos i. Se busca el máximo de la rama izquierda o el mínimo de la rama derecha. ii. Se sustituye el nodo a borrar por el nodo encontrado. Árbol Inicial: Árbol Final: Suprimir 46 Para el árbol inicial, eliminar las claves 24 21. Arbol inicial: Suprimir 24 (caso a): 21 21 24 4 Arbol inicial: Suprimir 21 (caso b): 21 48
Suprimir (caso c): Dos soluciones posibles : Árbol inicial: 4 Árbol inicial: Suprimir (caso c): 0 Arbol inicial: Suprimir (caso c): 1
Implementación de EliminarNodo void voideliminar (Nodo** r, r, TipoElemento dato) { if if (!(*r)) puts("nodo no no encontrado"); else elseif if (dato < (*r) (*r)-> -> dato) eliminar(&(*r) ->izdo, dato); else elseif if (dato > (*r) (*r)->dato) eliminar(&(*r) ->dcho,dato); else else { /* /* Nodo encontrado */ */ Nodo* q; q; /* /* puntero al al nodo nodo a suprimir */ */ q = (*r); (*r); /* /* r r es es el el ptr ptrdel nodo nodo Padre */ */ if if (q (q->izdo == == NULL) (*r) (*r) = q >dcho; else elseif if (q (q->dcho == == NULL) (*r) (*r) = q ->izdo; else else /* /* tiene tiene rama rama izquierda y derecha */ */ reemplazar(&q); free(q); Autor: Ing Rolando Simon Titiosky } } 2 Implementación de EliminarNodo void voidreemplazar(nodo** act) act) { Nodo* a, a, *p; *p; p = *act; *act; a = (*act) ->izdo; /* /* menores a IZQ*/ while (a (a->dcho) { p = a; a; /* /* buscar el el Mayor a DER*/ a = a ->dcho; } /* /* Cambio del del campo Datos */ */ (*act) ->dato = a ->dato; /* /* Al Al Abuelo p, p, se se hace hace cargo de de nieto nieto IZQ IZQ */ */ if if (p (p == == (*act)) p ->izdo = a ->izdo; else else p ->dcho = a ->izdo; (*act) = a; a; } 3 Otras Operaciones del TAD ABB Altura: retorna la altura de un árbol Construir: crea un árbol con un elemento raíz y dos ramas. Copiar: crear una copia del árbol CrearArbol: Inicia un árbol vacío Derecho: retorna la rama derecha de un árbol dado. Nodos: determina el número de nodos del árbol EsVacio: comprueba si el árbol tiene nodos Iguales: determinar si dos árboles son idénticos Izquierdo: retorna la rama izquierda de un árbol dado. Pertenece: determina si un elemento pertenece a un árbol. Recorrer: el árbol de acuerdo a algunos de los criterios Profundidad: determina la profundidad de un árbol dado Raiz: devuelve el nodo raíz. 4
Análisis de la complejidad de un ABB Si el árbol está bien balanceado, ningún camino de la raíz a una hoja tiene más de ( 1 + log 2 (n) ) nodos. Ejemplo: 21 h(a) = ( 1 + log 2 () ) 3 Análisis de la complejidad de un ABB Pueden ocurrir situaciones muy desfavorables: 41 Así, insertar un elemento i-ésimo toma O(i) 2 6 Análisis de la complejidad de un ABB Luego, el proceso de n inserciones toma : O n n + 1 i = O n i= 1 2 Se puede demostrar que el caso promedio en la inserción es : h(altura) = 1.4 log 2 (n); O(log 2 (n)) El caso promedio en hacer una operación Búsqueda, Eliminar, también lo son.
Ejercicios 1. Implementar una función que devuelva una lista con las hojas de un árbol binario de búsqueda. 2. Implementar una función que devuelva el nº de nodos externos de un árbol binario de búsqueda. 3. Escribir la función MAX_NODO que, suponiendo que el tipo base Elemento posee una relación de orden total, devuelva el mayor valor de los almacenados en un ABB. 4. Dado un árbol binario de búsqueda, hacer un función que devuelva la diferencia entre el mayor y el menor de los valores almacenados en dicho árbol. Hacerlo de forma no recursiva. 8 Ejercicios. Implementar un procedimiento al que se le pasan dos árboles binarios de búsqueda, y devuelve uno sólo, también binario de búsqueda, y que es el resultado de la mezcla de los dos anteriores. 6. Representar por medio de árboles las siguientes expresiones aritméticas: (x + y) * (a- b) [x + (y * z)] * c x * (y / -z) a + [(b * (c + d)] [a * (x + y)] * c x * y / [(a + b) * c] (x * y / a) + (b * c) Bibliografía - Webgrafía Introduction to Algorithms, 2nd edition. Cormen, T., Leiserson, Ch., Rivest, R. and Stein, C. MIT Press. 2001. Data Structures and Algorithms. A. Aho, J. Hopcroft, and J. Ullman. Addison-Wesley, 183. Traducido al castellano, 188. The Art of Computer Programming. Vol. 3: Searching and Sorting. Donald E. Knuth. Addison-Wesley, Massachusetts, 13. Traducido al castellano en Ed. Reverté, Barcelona. Programación Modular. ETSIT. Guión del profesor Juan Falgueras, Curso 200. Estructuras de Datos y Algoritmos, M.A. Weiss, Addison- Wesley Iberoamericana, 1. http://www.lcc.uma.es/~galvez/ftp/tad/tadtema4.pdf 60
Bibliografía - Webgrafía http://delta.cs.cinvestav.mx/~adiaz/anadis/bintree.pdf http://www.ucema.edu.ar/~rst/algoritmos_y_estructura_de_datos /Teoria/._Arboles_binarios.pdf http://www.madsgroup.org/docencia/alg/arboles_monticulos.pdf http://www.fdi.ucm.es/profesor/csegura/edi040/arboles.pdf http://www.iuma.ulpgc.es/users/jmiranda/docencia/programacion/ Tema_ne.pdf http://quegrande.org/apuntes/ei/1/edi/teoria/08-0/arboles_binarios_de_busqueda.pdf http://usuarios.multimania.es/sanjudas/download/resumenarboles.pdf 61