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 Conceptos, definiciones y terminología básica 3.2 Especificación e implementación del árbol binario 3.3 Recorridos sobre árboles binarios 3.4 Árboles binarios de búsqueda 3.5 Árboles equilibrados 3.6 Montículos y colas de prioridad 3.7 Árboles generales 3.8 Árboles multicamino de búsqueda 1
El TAD Árbol Duración 8 clases (12 ) Bibliografía Data Structures and Algoritms in C++ Autor: Micael T. Goodric, Roberto Tamassia, David M. Mount Editorial: Jon Wiley & Sons, Inc. Año: 2004 Págs. 253-301, 411-475 Estructuras de datos y métodos algorítmicos Autor: Narciso Martí Oliet y otros Editorial : Prentice-Hall, 2004 Págs. 147-230 Estructuras de datos: especificación, diseño e implementación Autor: Xavier Franc Gutiérrez Editorial : Ediciones UPC, 1999 Págs. 219-303 2
El TAD Árbol 3.1 Conceptos, definiciones y terminología básica Los árboles son estructuras que organizan sus elementos, denominados nodos, formando jerarquías. De entre estos nodos existe uno especial denominado raíz, situado en la cúspide de la jerarquía Existe una relación (de paternidad entre los nodos) que ace que la estructura sea jerárquica frente a la estructura lineal El uso de los árboles está muy extendido en programación. Algunos ejemplos pueden ser: estructurar los directorios y arcivos en los sistemas operativos representar la estructura de las fórmulas matemáticas organizar la información en los SGBD representar la estructura sintáctica de un programa fuente en los compiladores representar sistemas de clasificación 3
El TAD Árbol La definición recursiva de árbol es la siguiente: Un árbol n-ario (con n 1) es un conjunto no vacío de elementos o nodos del mismo tipo, tal que: es un único nodo, o bien está formado por un nodo raíz y m (0 m n) subconjuntos disjuntos, denominados subárboles, cada uno de los cuales es a su vez un árbol n-ario Un árbol con raíz x y subárboles A 1,, A m se representa de la siguiente forma: x A 1... A m 4
El TAD Árbol Podemos clasificar los árboles atendiendo a diferentes criterios: Cuando existe una relación de orden total en el conjunto de los subárboles de un árbol, el árbol se llama ordenado (será el que utilizaremos) Si no existe limitación para el número de ijos que pueda tener un nodo, el árbol se denomina general. Por el contrario, si existe un número fijo n que limita el número de ijos de un nodo, el árbol se denomina n-ario Cuando los nodos de un árbol contienen información (caso más abitual), el árbol se denomina etiquetado 5
El TAD Árbol Terminología Básica H A B C D E F G I J K L M Nodo: Cada posición dentro del árbol junto con la información asociada Si existe una arista (rama) dirigida del nodo n al nodo m, entonces n es el padre de m y m es un ijo de n Los ijos del mismo padre se denominan ermanos Todos los nodos de un árbol menos uno, denominado nodo raíz, tienen un único padre Una oja de un árbol es un nodo que no tiene ijos. El resto de los nodos se denominan interiores o internos 6
El TAD Árbol Terminología Básica A B C E F D G Se denomina camino del nodo n 1 al nodo n k a la secuencia de nodos de un árbol n 1, n 2,, n k, de tal forma que n i es el padre de n i+1 (1 i < k) La longitud de un camino es el número de nodos del camino menos 1. Por convenio, decimos que existe un camino de longitud 0 de un nodo a sí mismo H I J K L M Si existe un camino desde un nodo n 1 asta un nodo n 2, se dice que n 1 es antecesor de n 2, y n 2 es descendiente de n 1 El padre de un subárbol o nodo es su primer antecesor propio. Los ijos de un subárbol o nodo son sus primeros descendientes propios 7
El TAD Árbol Terminología Básica A B C D E F G H I J K L M La altura de un nodo en un árbol es la longitud del camino desde dico nodo a la oja más lejana que sea alcanzable desde él, más 1. La altura de un árbol es la altura del nodo raíz. El árbol vacío se considera con altura 0 La profundidad o nivel de un nodo en un árbol es la longitud del único camino existente desde el nodo raíz asta dico nodo Por definición, el número de niveles de un árbol se define como el nivel de la oja más profunda más 1. En el nivel 0 sólo está el nodo raíz. El número de niveles coincide con la altura del árbol El grado de un árbol n-ario es el número máximo de ijos que pueden tener sus subárboles El número máximo de nodos en el nivel i-ésimo de un árbol de grado n es n i 8
Árbol binario 3.2 Especificación e implementación del árbol binario Un árbol binario ordenado es un árbol en el que cada nodo puede tener a lo sumo dos ijos Es un conjunto de nodos del mismo tipo que, o bien es el conjunto vacío, o está formado por un nodo raíz enlazado a dos árboles binarios disjuntos denominados subárbol izquierdo y subárbol dereco t m k f d 9
Árbol binario Tipos de árboles binarios Un árbol binario de altura se llama completo si tiene todas sus ojas a nivel y todos sus nodos interiores tienen dos ijos no vacíos Un árbol binario de altura se llama semicompleto si los nodos de nivel y -1 son los únicos de grado cero o uno, de forma que las ojas del último nivel ocupan las posiciones más a la izquierda de dico nivel 50 20 80 10 40 74 99 8 35 60 10
Árbol binario Especificación Algebraica espec arbolesbinarios usa booleanos, enteros parámetro formal género elemento fpf género arbin operaciones : arbin _ < _, _ >: elemento arbin arbin arbin parcial raíz: arbin elemento parcial subizq, subder: arbin arbin vacío?: arbin booleano altura: arbin entero dominios de definición iz, de: arbin; e: elemento raíz (e<iz, de>) subizq (e<iz, de>) subder (e<iz, de>) 11
Árbol binario ecuaciones iz, de: arbin; e: elemento raíz (e<iz, de>) = subizq (e<iz, de>) = subder (e<iz, de>) = vacío? ( ) = vacío? (e<iz, de>) = altura ( ) = altura (e<iz, de>) = fespec Clasificación de las operaciones: Gen (arbin) = Mod (arbin) = Obs (arbin) = 12
Árbol binario Implementación del árbol binario La clase NodoB representa cada uno de los nodos de un árbol binario: obj izq der template <typename T> class NodoB { typedef NodoB<T>* PtrNodoB; public: NodoB(const T& objeto); NodoB(const T& objeto, PtrNodoB nizq, PtrNodoB nder); NodoB(const NodoB& n); const T& getobj() const; PtrNodoB getizq() const; PtrNodoB getder() const; void setobj(const T& objeto); void setizq(ptrnodob p); void setder(ptrnodob p); private: T obj; PtrNodoB izq, der; }; 13
Árbol binario raíz template <typename T> class Arbin { typedef NodoB<T>* PtrNodoB; public: Arbin(); Arbin(const T& objeto, const Arbin& ai, const Arbin& ad); Arbin(const Arbin& a); Arbin& operator=(const Arbin& a); const T& getraiz() const trow(arbolvacioexcepcion); const Arbin& subizq() const trow(arbolvacioexcepcion); const Arbin& subder() const trow(arbolvacioexcepcion); bool esvacio() const; int altura() const; private: PtrNodoB raiz; Arbin(PtrNodoB p); }; 14
Árbol binario Arbin(const T& objeto, const Arbin& ai, const Arbin& ad) inicio raiz = nuevo NodoB<T>(objeto, ai.raiz, ad.raiz) fin Arbin(PtrNodoB p) inicio raiz = p fin Arbin(const Arbin& a) var Arbin ci, cd fvar inicio si a.esvacio() entonces raiz = NULO sino ci = Arbin( a.subizq() ) cd = Arbin( a.subder() ) raiz = nuevo NodoB<T>( a.getraiz(), ci.raiz, cd.raiz ) fsi fin const Arbin<T>& subder() const trow(arbolvacioexcepcion) inicio si esvacio() entonces lanzar ArbolVacioExcepcion() fsi devolver *nuevo Arbin( raiz->getder() ) fin 15
El TAD Árbol Consideraciones sobre la implementación elegida La implementación elegida se ajusta tanto a la definición recursiva de árbol como a la especificación algebraica propuesta Sin embargo, deben tenerse en cuenta las siguientes consideraciones: El constructor Arbin(const T&, const Arbin&, const Arbin&) no ace una copia de los árboles a partir de los cuales se construye, sino que comparte estructura con ellos Las operaciones subizq y subder tampoco devuelven copias de los ijos izquierdo y dereco, respectivamente, sino subárboles que comparten memoria con el árbol original. Si se desea evitar la utilización de alias el coste de ejecución de esas operaciones sería O(n) en lugar de O(1) Por esa razón, no se a incluido un método destructor: la destrucción de variables locales podría afectar a otros árboles con los que compartieran estructura Una alternativa consistiría en la implementación de una clase Iterador, con métodos para avanzar al ijo izquierdo o dereco. Véase Goodric págs. 273-300 16
Árbol binario 3.3 Recorridos sobre árboles binarios - En el caso de recorridos en profundidad sobre árboles binarios, podemos distinguir tres tipos. En cualquier caso, si el árbol es vacío no se ace nada, y si no tiene ijos, se visita únicamente la raíz. PREORDEN Se visita la raíz, y a continuación, se recorren en preorden primero el subárbol izquierdo y luego el subárbol dereco POSTORDEN Se recorren en postorden primero el subárbol izquierdo y luego el subárbol dereco, y a continuación se visita la raíz INORDEN Primero se recorre en inorden el subárbol izquierdo, luego se visita la raíz, y por último se recorre en inorden el subárbol dereco - En el recorrido en ancura, los nodos se visitan por niveles y dentro de cada nivel de izquierda a dereca, comenzando por el nivel 0. 17
Árbol binario A B C D E F G H K I J Recorrido en preorden: Recorrido en inorden: Recorrido en postorden: Recorrido en ancura: 18
Árbol binario Recorrido en preorden template <typename T> void preorden(const Arbin<T>& a, Lista<T>& l) inicio si a.esvacio() entonces l.añadirdc( a.getraiz() ) preorden( a.subizq(), l ) preorden( a.subder(), l ) fsi fin Llamada al procedimiento de recorrido en preorden template <typename T> Lista<T> preorden(const Arbin<T>& a) var Lista<T> l fvar inicio preorden( a, l ) devolver l fin 19
Árbol binario template <typename T> void inorden(const Arbin<T>& a, Lista<T>& l) inicio si a.esvacio() entonces inorden( a.subizq(), l ) l.añadirdc( a.getraiz() ) inorden( a.subder(), l ) fsi fin template <typename T> void postorden(const Arbin<T>& a, Lista<T>& l) inicio si a.esvacio() entonces postorden( a.subizq(), l ) postorden( a.subder(), l ) l.añadirdc( a.getraiz() ) fsi fin template <typename T> void ancura(const Arbin<T>& a, Lista<T> & l) inicio Cola<Arbin<T> > c; Arbin<T> ac; si a.esvacio() entonces c.añadir(a); mientras ( c.esvacia()) acer ac = c.primero(); c.eliminar(); l.añadirdc(ac.getraiz() ); si ac.subizq().esvacio() entonces c.añadir(ac.subizq() ) fsi si ac.subder().esvacio() entonces c.añadir(ac.subder() ) fsi fmientras fsi Fin 20
Árboles Binarios de Búsqueda 3.4 Árboles binarios de búsqueda (ABB) Un ABB puede definirse cuando el tipo de los elementos posee una relación de orden total Son árboles binarios en los que: todos los valores de las claves del subárbol izquierdo son menores que el valor de la clave de la raíz todos los valores de las claves del subárbol dereco son mayores que el valor de la clave de la raíz esta propiedad se cumple en todos los nodos del árbol Propiedad: el recorrido en inorden de un ABB, independientemente de su forma, obtiene los elementos ordenados según la relación de orden existente entre los nodos 21
Árboles Binarios de Búsqueda Ejemplo de 2 árboles binarios con los mismos valores, pero con diferente estructura y altura: L P E P L B J E J B La máxima altura alcanzable por un ABB de n nodos se produce cuando el árbol degenera en una lista enlazada, en cuyo caso la altura es de n 22
Árboles Binarios de Búsqueda Operaciones básicas: Búsqueda Complejidad de las operaciones: O() Inserción altura del árbol Borrado Justificación log 2 (n) n i= 0 x i = n+ 1 x 1 x 1 Número máximo de nodos en el nivel i: 2 i Número máximo de nodos en un árbol binario: N N max 1 i 2 1 = 2 = = 2 1 2 1 i= 0 max 1 i = 2 = 2 + 2 + 2 +... + 2 i= 0 aplicando log 2 0 1 2 1 Progresión geométrica N = 2 1 2 = N + 1 = log ( N + 1) O(log ( n)) max max 2 max 2 23
Árboles Binarios de Búsqueda Las operaciones se basan en el esquema de búsqueda de un elemento en el árbol. Si A es un ABB y e el elemento a buscar, tenemos: Si A es el árbol vacío, el elemento e no está en el árbol. En caso contrario, se compara e con la raíz de A y se pueden dar tres casos: 1. e = raíz(a): el elemento a sido encontrado 2. e < raíz(a): se repite el proceso de búsqueda dentro del subárbol izquierdo de A 3. e > raíz(a): se repite el proceso de búsqueda dentro del subárbol dereco de A 24
Árboles Binarios de Búsqueda Operación de inserción Utiliza el esquema de búsqueda Si el elemento a insertar se encuentra en el árbol, no se ace nada En caso contrario, se inserta en el lugar donde acaba la búsqueda La búsqueda acaba sin éxito al llegar a un subárbol izquierdo o dereco que está vacío 8 8 6 10 insertamos el 5 6 10 3 7 3 7 5 25
Árboles Binarios de Búsqueda Operación de borrado (1/4) Utiliza el esquema de búsqueda Si no se encuentra el elemento a eliminar, la operación termina Si el elemento a eliminar se encuentra en el árbol, el comportamiento de la operación depende del número de ijos que tenga dico nodo: 1. Eliminar un nodo sin ijos (oja) simplemente se elimina el nodo 8 8 5 10 eliminamos el 3 5 10 3 6 6 26
Árboles Binarios de Búsqueda Operación de borrado (2/4) 2. Eliminar un nodo con un solo ijo solo ay que realizar una reasignación de punteros 11 25 37 11 25 37 el padre del nodo que queremos eliminar pasa a apuntar al ijo del nodo que está siendo eliminado 6 21 eliminamos el 21 6 15 15 17 17 27
Árboles Binarios de Búsqueda Operación de borrado (3/4) 3. Eliminar un nodo con dos ijos a. Se reemplaza el nodo que queremos eliminar con el elemento máximo de su subárbol izquierdo o el elemento mínimo de su subárbol dereco b. Seguidamente, se elimina el nodo máximo (o mínimo, según el caso) c. Dico nodo será una oja o tendrá un solo ijo, por lo que la operación se resolverá fácilmente mediante uno de los dos primeros casos 28
Árboles Binarios de Búsqueda Operación de borrado (4/4) Ejemplo de borrado 8 8 8 6 20 eliminamos el 20 6 17 6 17 5 15 21 5 15 21 5 15 21 12 17 12 17 12 16 16 16 29
Árboles Binarios de Búsqueda 3.4.1 Especificación algebraica espec arbolesbinariosdebusqueda usa booleanos parámetro formal género elemento operaciones _ _, _ _, _<_, _>_, _==_, _ _ : elemento elemento booleano fpf género abb operaciones : abb parcial _ < _, _ > : elemento abb abb abb parcial subizq, subder: arbin arbin vacío?: arbin booleano insertar: abb elemento abb está?: abb elemento booleano parcial min: abb elemento parcial max: abb elemento eliminar: abb elemento abb... 30
Árboles Binarios de Búsqueda dominios de definición iz, de: abb; e: elemento subizq (e<iz, de>) subder (e<iz, de>) min (e <iz, de>) max (e <iz, de>) e <iz, de> está definido sólo si (vacío?(iz) vacío?(de)) (vacío?(iz) vacío?(de) e < min(de)) ( vacío?(iz) vacío?(de) e > max(iz)) ( vacío?(iz) vacío?(de) e > max(iz) e < min(de)) ecuaciones iz, de: abb; e, e1, e2: elemento insertar(, e) = insertar(e1<iz, de>, e2) =... 31
Árboles Binarios de Búsqueda está? (, e) = está? (e1<iz, de>,e2) = min (e<iz, de>) = max (e<iz, de>) = eliminar(, e) = eliminar(e1<iz, de>, e2) = fespec 32
Árboles Binarios de Búsqueda 3.4.2 Implementación template <typename T> class ABB : public Arbin<T> { typedef NodoB<T>* PtrNodoB; public: ABB(); ABB(const ABB& a); const ABB& subizq() const trow(arbolvacioexcepcion); const ABB& subder() const trow(arbolvacioexcepcion); void insertar(const T& objeto); bool buscar(const T& objeto) const; const T& minimo() const trow(arbolvacioexcepcion); const T& maximo() const trow(arbolvacioexcepcion); void eliminar(const T& objeto); private: ABB(PtrNodoB p); }; 33
Árboles Binarios de Búsqueda void insertarnodo(const T& objeto, PtrNodoB& p) var PtrNodoB n fvar inicio si p == NULO entonces p = nuevo NodoB<T>(objeto) sino si objeto < p->getobj() entonces n = p->getizq() insertarnodo( objeto, n ) p->setizq( n ) sino si objeto > p->getobj() entonces n = p->getder() insertarnodo( objeto, n ) p->setder( n ) fsi fin void insertar(const T& objeto) inicio insertarnodo( objeto, raiz ) fin bool buscarnodo(const T& objeto, PtrNodoB p) inicio si p == NULO entonces devolver falso sino en caso de objeto == p->getobj() : devolver verdad objeto < p->getobj() : devolver buscarnodo( objeto, p->getizq() ) objeto > p->getobj() : devolver buscarnodo( objeto, p->getder() ) fcaso fsi fin bool buscar(const T& objeto) const inicio devolver buscarnodo( objeto, raiz ) fin 34
Árboles Binarios de Búsqueda const T& minimo() const trow(arbolvacioexcepcion) inicio si esvacio() entonces lanzar ArbolVacioExcepcion() fsi devolver minimonodo(raiz) fin const T& minimonodo(ptrnodob p) inicio si p->getizq() == NULO entonces devolver p->getobj() sino devolver minimonodo(p->getizq()) fin const T& maximo() const trow(arbolvacioexcepcion) inicio si esvacio() entonces lanzar ArbolVacioExcepcion() fsi devolver maximonodo(raiz) fin const T& maximonodo(ptrnodob p) inicio si p->getder() == NULO entonces devolver p->getobj() sino devolver maximonodo(p->getder()) fin 35
Árboles Binarios de Búsqueda void eliminar(const T& objeto) inicio eliminarnodo( objeto, raiz ) fin void eliminarnodo(const T& objeto, PtrNodoB& p) var PtrNodoB n fvar inicio si p NULO entonces si objeto < p->getobj() entonces n = p->getizq() eliminarnodo( objeto, n ) p->setizq( n ) sino si objeto > p->getobj() entonces n = p->getder() eliminarnodo( objeto, n ) p->setder( n )...... sino si p->getizq() == NULO entonces n = p p = p->getder() liberar n sino si p->getder() == NULO entonces n = p p = p->getizq() liberar n sino n = p->getizq() p->setobj(maximonodo(n)) eliminarnodo( p->getobj(), n ) p->setizq(n) fsi fsi fsi fin 36
Árboles binarios equilibrados 3.5 Árboles binarios equilibrados (AVL) La eficiencia de las operaciones sobre árboles binarios de búsqueda puede llegar a ser de O(n) en el peor de los casos En la práctica, dica eficiencia es de O(log 2 (n)), cuando suponemos que los valores se insertan en el árbol de una forma aleatoria. La eficiencia de las operaciones depende de la estructura del árbol en el momento de realizar la operación Lo ideal es, por tanto, que la altura del árbol sea siempre la menor posible Los árboles AVL, definidos por G.M. Adelson-Velskii y E.M. Landis en 1962, cumplen este requisito, por lo que se conocen también como árboles de búsqueda equilibrados 37
Árboles binarios equilibrados Diremos que un árbol binario está equilibrado si, para todos los nodos del árbol, la diferencia entre las alturas de sus subárboles siempre es menor o igual que 1. Todo nodo que sea oja está equilibrado Un árbol con un solo ijo está equilibrado si el árbol ijo consta de un único nodo 8 8 6 17 6 17 5 15 21 5 15 12 12 16 Árbol equilibrado Árbol no equilibrado 38
Árboles binarios equilibrados Cuando se realiza una operación de inserción o borrado en un árbol AVL, éste puede perder la propiedad de equilibrio. Para mantener dica propiedad se realiza una sencilla reorganización en el árbol denominada rotación n 2 n 1 n 1 T c T a n 2 rotar-dereca (n 2 ) T a T b T b T c rotar-izquierda (n 2 ) Con estas operaciones de rotación no se pierden las propiedades de ABB. En ambos árboles el nodo n 1 es menor que el nodo n 2, todos los elementos de T a son menores que n 1, todos los nodos de T c son mayores que n 2 y todos los nodos de T b están entre n 1 y n 2 39
Árboles binarios equilibrados rotar-dereca (10) 10 6 12 5 8 15 7 40
Árboles binarios equilibrados rotar-izquierda (10) 10 6 12 5 8 15 7 41
Árboles binarios equilibrados Factor de equilibrio de un nodo es la altura de su subárbol dereco menos la altura de su subárbol izquierdo. En un árbol equilibrado sólo podrá tener los valores -1, 1 o 0 Para representar un árbol AVL usaremos la misma estructura que para los ABB La clase nodob se amplía con un nuevo atributo que almacena su factor de equilibrio -1 1 8 1 6 17 0-1 0 5 15 21 0 12 42
Árboles binarios equilibrados Operación de búsqueda Puesto que los árboles AVL son un caso particular de ABB, usamos el mismo algoritmo de búsqueda pero con la particularidad que siempre se realizará con una eficiencia de O(log 2 n) Operación de inserción La inserción de un nodo en un árbol AVL consta de dos fases: usando el algoritmo de inserción desarrollado para los ABB, se recorre el camino partiendo del nodo raíz y se inserta como una oja del árbol en su lugar correspondiente se recorre el camino de vuelta acia la raíz, actualizando los equilibrios de los nodos y reequilibrando el árbol cuando sea necesario, esto es, cuando la altura de uno de sus nodos pase a ser ±2 43
Árboles binarios equilibrados El desequilibrio se produce cuando, para un determinado nodo, la altura de su subárbol dereco es mayor que la de su subárbol izquierdo y el nuevo nodo se inserta por el subárbol dereco, o si la altura de su subárbol izquierdo es mayor que la de su subárbol dereco y el nuevo nodo se inserta por el subárbol izquierdo n n T i T d + 1 + 1 T i T d caso (a) caso (b) Las situaciones de desequilibrio se solucionan mediante 2 tipos de rotaciones: patrón de rotación simple patrón de rotación doble 44
Árboles binarios equilibrados Rotación simple a la izquierda (I) Es necesario aplicarlo cuando el nuevo nodo se inserta en el subárbol dereco del subárbol dereco de n en el caso (a) +1 +2 n n T a n 1 0 T a n 1 +1 T b T c T b T c + 1 45
Árboles binarios equilibrados Para reestablecer la propiedad de equilibrio, se realiza una rotación simple a la izquierda sobre el nodo n 0 n 1 0 n T c + 1 T a T b 46
Árboles binarios equilibrados Rotación simple a la dereca (D) Es el caso simétrico al anterior y es necesario aplicarlo cuando el nuevo nodo se inserta en el subárbol izquierdo del subárbol izquierdo de n en el caso (b) -2-1 n n -1 0 n 1 T c n 1 T c T a T b T a T b + 1 47
Árboles binarios equilibrados Para reestablecer la propiedad de equilibrio, se realiza una rotación simple a la dereca sobre el nodo n 0 n 1 T a n 0 + 1 T b T c 48
Árboles binarios equilibrados Rotación doble dereca-izquierda (DI) Es necesario aplicarlo cuando el nuevo nodo se inserta en el subárbol izquierdo del subárbol dereco de n en el caso (a) n +1 n +2-1 0 n 1 T a 0 n 1 T a +1 n 2 n 2-1 T b -1 T c T d -1 T b T c T d 49
Árboles binarios equilibrados Para reestablecer la propiedad de equilibrio, se realiza rotación doble DI, es decir, una rotación a la dereca sobre el nodo n 1 seguida de otra rotación a la izquierda sobre el nodo n n 0 n 2 T a n 2-1 0 n n 1-1 T b n 1 T c T d -1 T c T b T a T d proceso intermedio resultado final 50
Árboles binarios equilibrados Rotación doble izquierda-dereca (ID) Es necesario aplicarlo cuando el nuevo nodo se inserta en el subárbol dereco del subárbol izquierdo de n en el caso (b) -1 n -2 n 0 +1 n 1 n 1 0 T d +1 n 2 T d n 2 T a -1-1 T b T c T a T b -1 T c 51
Árboles binarios equilibrados Para reestablecer la propiedad de equilibrio, se realiza rotación doble ID, es decir, una rotación a la izquierda sobre el nodo n 1 seguida de otra rotación a la dereca sobre el nodo n n n 2 0-1 0 n 2 Td n 1 n n 1 T a T b - 1 T c -1 T b T a T d T c proceso intermedio resultado final 52
Árboles binarios equilibrados Tanto en las rotaciones simples como en las rotaciones dobles que se realizan en la inserción, la altura del árbol resultante tiene la misma altura que el árbol original. Esta propiedad es importante, ya que permite finalizar el algoritmo de inserción sin necesidad de seguir observando los nodos por el camino de vuelta asta el nodo raíz, puesto que no se encontrará desequilibrado. Durante la etapa de recorrido de regreso del procedimiento de inserción, lo que necesitamos es encontrar el primer nodo cuyo equilibrio cambia de ±1 a ±2. A este nodo se le llama pivote. Una vez encontrado el pivote, se lleva a cabo la rotación apropiada según uno de estos casos: 1. si el equilibrio del pivote pasa a ser +2 y el equilibrio de su ijo dereco es +1, se realiza una rotación simple a la izquierda. 2. si el equilibrio del pivote pasa a ser +2 y el equilibrio de su ijo dereco es -1, se realiza una rotación doble DI. 3. si el equilibrio del pivote pasa a ser -2 y el equilibrio de su ijo izquierdo es -1, se realiza una rotación simple a la dereca. 4. si el equilibrio del pivote pasa a ser -2 y el equilibrio de su ijo izquierdo es +1, se realiza una rotación doble ID. 53
Árboles binarios equilibrados Operación de borrado Se utiliza la misma técnica que el algoritmo de eliminación para ABB Una vez eliminado se recorre el camino desde el padre del nodo eliminado asta el nodo raíz, actualizando los equilibrios Si se encuentra un nodo cuyo equilibrio pasa a ser ±2, se utiliza un patrón de rotación simple o doble para reestablecer la propiedad de equilibrio A diferencia de la operación de inserción, la altura de un árbol puede no mantenerse después de una operación de eliminación y reequilibrado, por lo que puede requerir más de una operación de reequilibrado para mantener la propiedad 54
Árboles binarios equilibrados La casuística que se puede dar en una operación de borrado de un árbol AVL es la siguiente: 1. Si el equilibrio del padre pasa de 0 a ±1, el algoritmo termina, ya que la altura del árbol no se modifica 2. Si el equilibrio del padre pasa de ±1 a 0, continuar reequilibrando los nodos 3. Si el equilibrio del padre pasa de +1 a +2 3.1. Si el equilibrio del ijo dereco es -1 rotación doble DI (continuar) 3.2. Si el equilibrio del ijo dereco es 0 o +1 rotación simple a la izquierda (a) si el equilibrio del ijo dereco es 0, el algoritmo termina (b) si el equilibrio del ijo dereco es +1, continuar 4. Si el equilibrio del padre pasa de -1 a -2 4.1. Si el equilibrio del ijo izquierdo es +1 rotación doble ID (continuar) 4.2. Si el equilibrio del ijo izquierdo es 0 o -1 rotación simple a la dereca (a) si el equilibrio del ijo izquierdo es 0, el algoritmo termina (b) si el equilibrio del ijo izquierdo es -1, continuar 55