Árboles Representación y manipulación de árboles: búsqueda y recorrido = listas ramificadas El grado del árbol refiere a la cantidad (máxima) de ramos que sale de cada nodo. El primer nodo se llama la raíz del árbol. Los últimos nodos se llaman las hojas. Los nodos que no son hojas se dicen nodos de ruteo. Si nodo a apunta a nodo b, a es padre de b y b es hijo de a. Dos nodos que comparten padre son hermanos. Orden de árbol ! Cada nodo contiene un dato. ! Para ordenamiento, se requiere una función de precedencia y una regla de orden del árbol. ! La regla establece el orden relativo de los datos del padre y sus hijos. ! El grado de un nodo es la cantidad de hijos que tiene. ! En árboles ordenados, también el orden de los hijos de un nodo se tiene que fijar (de izquierda a derecha). ! Depende de la aplicación si habrá datos duplicados o si serán únicos todos. Estructura típica de un nodo Puntero a su padre nulo si es raíz x Dato <x >x Grado cero si es hoja Punteros a los hijos en lista o arreglo 2k ≤ n < 2k+1. } else { ubicar(clave, actual.izquierdo); (6.4) La altura de un ramo de un vértice v, es decir, un subárbol la raı́z de cual es v e } de v. La altura del árbol entero es la altura de su raı́z. Un árbol balanceado binarios son una clase de árbol en uso muy común. En un árbol binario, cada } árbol esta caracterizar como un árbol con raı́z vr con A(vr ) = O (log n). La condición d La condicióndos que utilizamos decidirsu si ohijo no unizquierdo dado se llama ue no es una hoja tiene al máximo vérticespara hijos: ybalanceado su hijo } AVL es que ∀v ∈ V la condición de balance AVL [2]; también existen otras condiciones. Para formular la Para un ejemplo, ve la figura 6.3. hay Si que ningún tiene solamente un hijo, se |A(izq(v)) − A(der(v))| ≤ 1. condición, definir lavértice altura de un vértice: Árbol binario Altura y profundidad ! el árbol está lleno. 1, si v es una hoja Para unas cotas sobre la forma del árbol,esdefinimos además la profundid igual a! kLa − profundidad 1. En derivar este caso, hojas delde árbol (6.5) es de de el unnúmero nodo la cantidad pasosnque uno tiene que bajar máx{A(izq(t)), A(der(t))} + 1, si vdesde es vértice delaruteo. del árbol: ! raíz para bajar a ello: k 0, si la raı́z 2D(v) ≤ n=< 2k+1 . v es la raı́z, (6.4) La altura de un ramo de un vértice v, es decir, un subárbol la raı́z de cual es v es la altura D(v.P) + 1, en otro caso. de v. La altura del árbol entero es la altura de su raı́z. Un balanceado se que puede ! árbol El conjunto de nodos tienen la misma profundidad entre ellos se llama unque Laque profundidad del árbol entero simplemente máx Aplica D=A La condición utilizamos para decidir si oesno un dado árbol esta balanceado se llama v D(v). caracterizar como un árbol con raı́z vr con A(vr ) = O (log n). La condición de balance nivel. la condiciónDenotamos de balancepor AVL también existenen otras Para formular la a n el[2]; numero de vértices totalcondiciones. y por H el numero de hojas del ! La altura de un nodo es la cantidad máxima de pasos necesarios para subir a hijo derecho izquierdoAVL es que ∀v ∈ V condición, hay que definir la altura de un vértice: = 2k, |A(izq(v)) − A(der(v))| ≤ 1. ello todo desdenuna hoja,tenemos más(6.6) uno:H = 2n − 1 y D = log2 n. Para ubicar a una clave a prof ! toma exactamente d pasos en el árbol, es decir, tiempo O (d). Entonces, para 1, si v es una hoja A(v) = (6.5) Para derivar unas cotas sobre la forma del árbol, definimos ademásperfectamente la profundidad de cada de H hojas, se puede localizar una clave en tiempo balanceado máx{A(izq(t)), A(der(t))} + 1, si v es de ruteo. vértice del árbol: ! ! La profundidad de un árbol es la O profundidad máxima de sus nodos. 0, si v es la raı́z, (D) = O (log O (log . v es la altura 2 H) 2 n)es La altura de un ramo de un vértice la=raı́z de cual D(v) (6.7)v, es decir, un subárbol ramo derecho de =la raı́z D(v.P) + 1, en otro caso. alturadel de un árbol es la altura su raíz. de v. !LaLa altura árbol entero es la de altura de su raı́z. Un árbol balanceado se puede CAP ÍTULO 6. ESTRUCTURAS DE DATOS ! Aplica como un árbol con raı́z v con A(v La profundidad del árbol entero es simplemente máxcaracterizar D(v). Aplica que D = A − 1. r r ) = O (log n). La condición de balance v AVL es que ∀v ∈ V ! El balanceo árbol Para es la tarea de minimizar su altura. Denotamos por n el numero de vértices en total y por H el numero de hojasde delunárbol. |A(izq(v)) − A(der(v))| ≤ 1. (6.6) todo n = 2k, tenemos H = 2n − 1 y D = log n. Para ubicar a una clave a profundidad d A(v) = hijo Figura 6.3: Un ejemplo de un árbol binario.2 toma exactamente d pasos en el árbol, es decir, tiempo O (d). Entonces, para cada árbol Para derivar unas cotas sobre la forma del árbol, definimos además la profundidad de cada perfectamente balanceado de H hojas, se puede localizar una clave en tiempo vértice del árbol: ! relativamente fácil también para bases de datos muy grandes,D(v) = 0, si v es la raı́z, (6.7) O (D) = O (log2 H) = O (log2 n) . (6.8) D(v.P) + 1, en otro caso. como ı́ndices es ferentes ramos y partes del árbol se puede guardar en diferentes páginas de la Búsqueda en árboles binarios La profundidad del árbol entero es simplemente máxv D(v). Aplica que D = A − 1. Balance: peor caso y mejor caso a fı́sica de la computadora. La figura 6.4 contiene un ejemplo, adaptado de Knuth 6.4: Un ejemplo de cómo dividir un árbol de ı́ndice en varias páginas de memoria: n = número de nodos en el árbol as agrupan juntos subárboles del mismo tamaño. Denotamos por n el numero de vértices en total y por H el numero de hojas del árbol. Para boolean busca(int valor, arbol* nodo) { todo n = 2k, tenemos H = 2n − 1 y D = log2 n. Para ubicar a una clave a profundidad d if (nodo.dato == valor) { toma exactamente d pasos en el árbol, es decir, tiempo O (d). Entonces, para cada árbol return deperfectamente inserción de true; losde H hojas, se puede localizar una clave en tiempo balanceado } else if (nodo.grado == 0) { ema con árboles binarios es que su forma depende del orden os y en el peor caso puede reducir a casi una lista (ver la figura 6.5). Asintóticamente logarítmico. Un árbol balanceado con n = 8 y profundidad tres. El peor caso de falta de balance para n = 8 tiene profundidad seis. Asintóticamente lineal. 6.5: Un árbol binario de peor caso versus un árbol binario de forma óptima, ambos o vértices hojas. return false; O (D) = O (log2 H) = O (log2 n) . } else if (nodo.dato > valor) { return busca(valor, nodo.izquierdo); } else { return busca(valor, nodo.derecho); } int main() { } ... busca(valor, raiz); ... } (6.8) A(v) = Complejidad asintótica ! 1, si v es una hoja Figura 6.6: La inserción de un elemento nu máx{A(izq(t)), A(der(t))} v es creación + de un 1, vérticesi de ruteo nuevode c, hijo Sin embargo, los valores 1 y 2 también apar La altura de un ramo de un Condiciones vértice v, es decir, un subárbol de55 0, 1, 1, 2,la 3, 5, raı́z 8, 13, 21, 34, de balance: AVL — F (2) y F (3)! Entonces, podemos es de v. La altura del árbol entero es la altura de Esto su¡sonnosraı́z. Un árbol b da ! Esto requiere en el peor caso una cantidad de pasos R(a) = F (a La diferencia de alturas de los dos hijos de unO nodo nunca n). como un árbol !con raı́z v con A(v ) = (log La c igual a la profundidad caracterizar del árbol. r r R(a) −2 = debe exceder a uno: ! En un árbol no balanceado, la profundidad del peor log (R(a) + 2) = log AVL es que ∀v ∈ V caso es lineal. log (R(a) + 2) = a + a ≈ 1,44 |A(izq(v)) − A(der(v))| ≤ 1. ! En un árbol balanceado, la profundidad del peor caso ! En el peor caso el resultado es falso y buscamos hasta llegar a una hoja. a+ φ√ 5 φ φ φ Ya sabemos que n > R(A) porque H > 0 pletamente vacı́o. Entonces aplica que sigui es logarítmica. ! Conviene mantener los árboles en balance si el esfuerzo requerido para ello es menor a lineal. Por la un análisis matemático involucra ladefinimos serie de Fibonacci, se cada llega árbol a Teorema 6.31. Para que cump Para derivar unas cotas sobre forma delqueárbol, la 96 CAPÍTULO 6. ESTRUCTURAS además DE DATOS demostrar que la altura resultante es menor a 1,440 log(n + 2) − 0,328. vértice del árbol: ! Para insertar un elemento nuevo al árbol de de la clave del elemento. Llegando a la hoja 0, si v es la raı́z, un vértice de ruteo v nuevo. La hoja v va D(v) = otro hijo será un vértice nuevo v creado par D(v.P) + 1, menor endeotro caso. v y v será el hijo izquierdo y e a c r b h c n h n Tipos de rotaciones Rotaciones La profundidad del árbol entero es simplemente máx D(v). Aplica de ruteo vr ası́ creado será igual al valor d Figura 6.7: Al eliminar una hoja con clave b, también suejemplo. padre, el vértice de ruteo con el valor a está eliminado. v un elemento del árbol, hay qu Para eliminar v t inar además de lau hoja su vértice de ruteo t ruteo t u v vh a la posición tque ocupó vr . La figu v u Denotamos por n el numero de vértices en total y por H el numero de Las operaciones de insertar y eliminar clav tiempo de acceso O (log n) está solame todo n = 2k, tenemos H = 2n − 1 y D = log2 n. deestá Para ubicar a siuna c perfectamente balanceado su estruct de la raı́z a cada hoja: todas las hojas están e exactamente ! Las rotaciones procedentoma recursivamente hacia la raíz hasta d pasos en el árbol, es decir, tiempo O (d). Enton que ya no haya imbalance. perfectamente balanceado de H hojas, se puede localizar una clave e ! Cuando un nodo llega a detectar un imbalance (por haber añadido o eliminado un nodo del árbol), se atiende el problema a través de la realización de rotaciones. u B B B Rotación simple derecha t w u Van a ser por máximo una cantidad logarítmica de rotaciones si cada imbalance está atendida inmediatamente después de haberse presentado. t u v t w u v v w A B A Rotación simple izquierda ! v A A A v t w u A B B1 B2 B O (D) = O (log2 H) = O (log2 n) . B1 B2 Rotación doble izquiera-derecha A1 A1 A2 A2 Rotación doble derecha-izquierda Figura 6.8: Cuatro rotaciones básicas de árboles binarios para restablecer balance de las alturas de los ramos. 6.3. ÁRBOLES Condiciones de rotación propiedades de los ramos determinan cuál rotación será implementada en v A(A) ≥ A(B) ⇒ rotación simple a la derecha, A(u) ≥ A(v) + 2 : A(A) < A(w) ⇒ rotación doble izquierda-derecha, A(A) ≥ A(B) ⇒ rotación simple a la izquierda, A(u) ≤ A(v) − 2 : A(B) < A(w) ⇒ rotación doble derecha-izquierda. Árboles externos 97 ! Los datos se guardan únicamente en las hojas. ! Los nodos de ruteo contienen claves de rastreo que no necesariamente están presentes actualmente como datos en el árbol. ! Inserción y eliminación de datos resulta mucho más simple en este tipo de árboles. CAPÍTULO 6. ESTRUCTURAS DE DATOS 92 (6.15) Con esas rotaciones, ninguna operación va a aumentar la altura de un ramo, pero la puede reducir por una unidad. La manera tı́pica de encontrar el punto de rotación t es regresar hacı́a la raı́z después de haber operado con una hoja para verificar si todos los vértices Figura 6.4: Un ejemplo de cómo dividir un árbol de ı́ndice en varias páginas de memoria: en camino todavı́a cumplan con la condición de balance. La complejidad asintótica de agrupan juntos subárboles del mismo tamaño. las lı́neas buscar una hoja toma O (log n) tiempo, la operación en la hoja tiempo constante O (1), la “vuelta” hacı́a la raı́z otros O (log n) pasos, y cada rotación un tiempo constante O (1). Si al ejecutar una rotación, la altura de t cambia, habrá que continuar hacı́a la raı́z porque otras faltas de balance pueden técnicamente haber resultado. Si no hay cambio en la altura de t, no hay necesidad de continuar más arriba en el árbol. . ÁRBOLES 96 Inserción 95 6.3.3. Árboles rojo-negro CAPÍTULO 6. ESTRUC Eliminación Un árbol balanceado con n = 8 y profundidad tres. El peor caso de falta de balance para n = 8 tiene profundidad seis. Otro tipo de árboles binarias son los árboles rojo-negro (inglés: red-black tree) . Las reglas para mantener orden de las claves es las mismas. También ofrecen tiempo de acceso 6.5: Un árbol binario de peor caso versus un árbol binario de forma óptima, ambos c En vez de la condición Figura a y actualización O (log n) y se balancea por rotaciones. AVL, se vértices a hojas. c con ocho identifica vértices fuera de balance por asignar colores a los vértices. Un árbol rojo-negro cumple las siguientes propiedades: 6.3.2. Árboles AVL (I) Cada vértice tiene exactamente uno deblos dosacolores: rojo y negro. (II ) La raı́z es negro. Agregamos a un nodo con dato b < a b (de Adel’son-Vel’skii c Árboles AVL y Landis [2]) son árboles binarios que aseguran complejidad asintótica O (log n) para las operaciones básicas de ı́ndices. La variación de árboles AVL que estudiamos acá guarda toda la información en sus hojas ura 6.6: La inserción de un elemento nuevo con la clave b tal que b < a resulta en los la vértices “internos” para información utilizado al realizar las operaciones del y utiliza (III ) Cada hoja es negro. ación de un vértice de ruteo nuevo c, hijos del cual serán los vértices hojas deı́ndice. a y b.Los vértices que no son hojas ahora se llaman vértices de ruteo . El orden del árbol es tal quehoja todas las hojas ramo del hijo contienensu clavespadre, menores que el el v Figura 6.7: Al eliminar valor una conen elclave b, izquierdo también del vértice de ruteo y todas las hojas en el ramo del hijo derecho contienen claves (IV ) Si un vértice es rojo, sus ambos hijos son negros. Con esas rotaciones, ninguna operación va a au reducir por una unidad. La manera tı́pica de e hacı́a la raı́z después de haber operado con u en camino todavı́a cumplan con la condición buscar una hoja toma O (log n) tiempo, la op la “vuelta” hacı́a la raı́z otros O (log n) pasos, Sioalnegro. ejecutar una rotación, la altura de t cambi 1. Cada nodo es o rojo otras faltas de balance pueden técnicamente ha 2. La raíz es negra. de t, no hay necesidad de continuar más arriba Condiciones de balance: rojo-negro Practicamos ! Escriban, en pares, en pseudocódigo para ! Búsqueda de un dato en un árbol externo que no contiene claves duplicados ! Inserción de un dato a un árbol externo que no permite insertar una clave que ya está incluida ! 3. Las hojas son negras. 4. Se un nodo es rojo,6.3.3. ambos susÁrboles hijos son negros. rojo-negro Eliminación de un dato de un árbol externo que no contiene claves duplicados 5. Para cada nodo, todos los caminos de ello a alguna hoja Otro tipo dedenodos árboles binarias son contienen la misma cantidad negros. los árboles reglas para mantener orden de las claves es las y actualización Altura resultante es O (log n) .y se balancea por ro identifica vértices fuera de balance por asignar cumple las siguientes propiedades: (I) Cada vértice tiene exactamente uno de l Árboles (II ) La raı́z esB negro. Rotaciones en árboles rojo-negro CAPÍTULO 6. ESTRUCTURAS DE DATOS 98 (III ) Cada hoja es negro. Árboles balanceados. ! Ni binarios ni externos. (IV ) Si un vértice es rojo, sus ambos hijos so ! Cada nodo de ruteo debe contener un máximo (V) Para todos K losescaminos de de 2K - 1 y un mínimo decada K - 1vértice datosv,donde número de nodos negros. una constante. ! La raíz puede tener menos de K - 1 datos. Entonces, la estructura de un vértice contiene ! Si un nodo de ruteo contiene k datos, va a tener y los dos hijos, un color. Aplica para los árbo necesariamenteque k +la1expresión hijos. exacta tiene cota superior 2 lo ! Las hojas son especiales que no tienen hijos. con rotac Los árbolesyarojo-negro se balancea hojas nuevas, además de las rotaciones para res ! Rotación a la izq. v Rotación a la der. w w v A C B C A B Figura 6.9: Las dos rotaciones de los árboles rojo-negro son operaciones inversas una para la otra. algunos vértices en el camino desde la hoja nueva hasta la raı́z. Las posibles violaciones Estructura típica en árboles B 100 Ejemplo CAPÍTULO 6. ESTRUCTURAS DE D CAPÍTULO 6. ESTRUCTURAS DE D 100 Puntero a su padre nulo si es raíz: opcional Grado cantidad de claves Datos en un arreglo Punteros a los hijos en otro arreglo Si es hoja variable binaria + 6 15 32 + 1 3 4 5 + 8 9 12 + 14 18 21 25 29 36 42 56 73 splay(+∞, A) A) splay(+∞, ¿Cómo es la regla del orden del árbol? Figura 6.10:6.10: La unión de dos árboles biselados. Figura La unión de dos árboles biselados. son menores o iguales una clave como parámetro y lasmayores mayoresestán estánen en son menores o iguales a unaa clave dadadada como parámetro y las árbol. árbol. Árboles biselados Operación splay(A,� ) La operación básica utilizada para implementar todas estas operaciones es splay La operación básica utilizada para implementar todas estas operaciones es splay quesplay hace splay es convertir el árbol a tal forma que el vérticecon conclave clave!!es es hacer que claveforma enque la raíz árbol biselado A. � esté lo quelohace es convertir el =árbol A alaAtal eldel vértice si presente, y en la ausencia de ! en A, la raı́z será si presente, y en la ausencia de ! enSi AA,nola raı́z aserá contiene �, la nueva raíz será ! Binarios. ! No externos. ! Claves deben ser únicas. ! Menores a la izquierda, mayores a la derecha. ! ! máx {k ∈ A | ! > k} si A contiene claves mayores a � y No hay una condición de balance. si A contiene claves menores a ! y mı́n {k ∈ A} en otro caso. El orden de las Tiempo logarítmico para búsqueda, inserción, eliminación Aárbol contiene claves menores a ! yelmı́n {k ∈ A} en de otro caso. El claves. orden de las de datos y para la unión si de un menor a un árbol mayor después de la operación cumple mismo requisito orden de las máx {k ∈ A | ! > k} otro caso.requisito de orden de las claves. después de la operación cumple elenmismo en términos de las claves o división de un árbol a parte menor y mayor Las operaciones están implementadas de la manera siguiente utilizando splay: Las operaciones están implementadas de la manera siguiente utilizando splay: búsqueda de ! en A: ejecuta splay(!, A). Si la raı́z en el resultado es !, la es “sı́”, caso “no”.splay(!, A). Si la raı́z en el resultado es !, la búsqueda deen! otro en A: ejecuta ! ! ! ! ! Búsqueda de valor v: Haz splay(A, v). Unión: Haz un splay con infinito en el árbol menor. Junta el árbol mayor como el ramo derecho del resultado. División con valor v: Haz splay(A, v). El ramo derecho será la parte mayor y el resto será la parte menor. Insertar valor v: ! Divide A usando v. ! Si c ya está en la raíz, junta los ramos. ! Si no es, crea una raíz nueva para v y pon los ramos como sus hijos. Eliminar valor v: ! Divide A usando v. ! Si v no es la raíz, no hagas nada. ! Si lo es, quítalo y une los dos ramos. Operaciones Montículos = estructuras formadas por grupos de árboles 6.4. MONTÍCULOS 103 Ejemplo: montículo binómico Figura 6.13: Un ejemplo de un montı́culo binómico, compuesto por cinco árboles binómicos. Recorridos de árboles ! Iniciando de la raíz, se visita a cada nodo del árbol ! Llegando a un nodo, se visita primero de manera recursiva el ramo izquierdo y luego el ramo derecho ! El momento en que se imprime el nodo determina el orden de salida ! Antes del ramo izquierdo: en preorden ! Después del ramo derecho: en postorden ! Entre los ramos: en órden interno Cada vértice del montı́culo tiene guardado además de su propia clave, su grado (en este contexto: el número de hijos que tiene) y tres punteros: a su padre, a su hermano y a su hijo directo. La operación de encadenación forma de dos árboles Bn un árbol Bn+1 tal que el árbol Bn con clave mayor a su raı́z será un ramo del otro árbol Bn . Esta operación se realiza en preorden(nodo) tiempo O (1). void { Pseudocódigos imprime nodo.valor; Para unir dos montı́culos binómicos, hay que recorrer las listas de raı́ces de los dos si simultaneamente. (nodo.izq ≠ Al nulo) { preorden(nodo.izq); montı́culos encontrar dos árboles del mismo tamaño}Bi , se los junta siBi+1 (nodo.der ≠ nulo) { preorden(nodo.der); a un árbol . Si uno de los montı́culos ya cuenta con un Bi+1 se los}junta recursiva} Si hay dos, uno queda en el montı́culo final como un árbol independiente mientras mente. void { operación necesita O (log n) tiempo. en otro se unepostorden(nodo) con el recien creado. Esta if (nodo.izq ≠ nulo) { postorden(nodo.izq); } Entonces, para insertar un elemento, creamos un B0 en tiempo O (1) y lo juntamos en el if (nodo.der ≠ nulo) { postorden(nodo.der); } montı́culo en tiempo O (log n), dando una complejidad total de O (log n) para la inserimprime nodo.valor; ción. } Para void eliminarordenint(nodo) el elemento mı́nimo,{ lo buscamos en tiempo O (log n), le quitamos y creamossi otro(nodo.izq montı́culo de sus hijos en {tiempo O (log n). Unimos los dos ≠ nulo) ordenint(nodo.izq); } montı́culos en tiempo O (log n). Entonces el tiempo total para esta operación es también O (log n). imprime nodo.valor; si (nodo.der ≠ nulo) { ordenint(nodo.der); } más cerca de Para disminuir el valor de una clave, levantamos el vértice correspondiente } la raı́z para no violar el orden del montı́culo en tiempo O (log n). Para eliminar un elemento cualquiera, primero disminuimos su valor a −∞ en tiempo O (log n) y después quitamos el mı́nimo en tiempo O (log n).