You are on page 1of 18

rbol rojo-negro

rbol rojo-negro
Un rbol rojo negro es un tipo abstracto de datos, concretamente es un rbol binario de bsqueda equilibrado, una estructura de datos utilizada en informtica y ciencias de la computacin. La estructura original fue creada por Rudolf Bayer en 1972, que le dio el nombre de rboles-B binarios simtricos, pero tom su nombre moderno en un trabajo de Leo J. Guibas y Robert Sedgewick realizado en 1978. Es complejo, pero tiene un buen peor caso de tiempo de ejecucin para sus operaciones y es eficiente en la prctica. Puede buscar, insertar y borrar en un tiempo O(log n), donde n es el nmero de elementos del rbol. Sera ideal exponer la especificacin algebraica completa de este tipo abstracto de datos (TAD) escrita en algn lenguaje de especificacin de TADs como podra ser Maude; sin embargo, la complejidad de la estructura hace que la especificacin quede bastante ilegible, y no aportara nada. Por tanto, explicaremos su funcionamiento con palabras, esquemas e implementaciones de funciones en el lenguaje de programacin C.

Terminologa
Un rbol rojo-negro es un tipo especial de rbol binario usado en informtica para organizar informacin compuesta por datos comparables (como por ejemplo nmeros). En los rboles rojo-negro las hojas no son relevantes y no contienen datos. A la hora de implementarlo en un lenguaje de programacin, para ahorrar memoria, un nico nodo (nodo-centinela) hace de nodo hoja para todas las ramas. As,todas las referencias de los nodos internos a las hojas van a parar al nodo centinela. En los rboles rojo-negro, como en todos los rboles binarios de bsqueda, es posible moverse ordenadamente a travs de los elementos de forma eficiente si hay forma de localizar el padre de cualquier nodo. El tiempo de desplazarse desde la raz hasta una hoja a travs de un rbol equilibrado que tiene la mnima altura posible es de O(log n).

Propiedades
Un rbol rojo-negro es un rbol binario de bsqueda en el que cada nodo tiene un atributo de color cuyo valor es rojo o negro. Adems de los requisitos impuestos a los rboles binarios de bsqueda convencionales, se deben satisfacer los siguientes para tener un rbol rojo-negro vlido: 1. Todo nodo es o bien rojo o bien negro. 2. La raz es negra. 3. Todas las hojas son negras (las hojas son los hijos nulos). 4. Los hijos de todo nodo rojo son negros (tambin llamada "Propiedad del rojo"). 5. Cada camino simple desde un nodo a una hoja descendiente contiene el mismo nmero de nodos negros, ya sea contando siempre los nodos negros nulos, o bien no contndolos nunca (el resultado es equivalente). Tambin es llamada "Propiedad del camino", y al nmero de nodos negros de cada camino, que es constante para todos los caminos, se le denomina "Altura negra del rbol", y por tanto el cmino no puede tener dos rojos seguidos. 6. El camino ms largo desde la raz hasta una hoja no es ms largo que 2 veces el camino ms corto desde la raz del rbol a una hoja en dicho rbol. El resultado es que dicho rbol est aproximadamente equilibrado.

Un ejemplo de rbol rojo-negro

rbol rojo-negro Dado que las operaciones bsicas como insertar, borrar y encontrar valores tienen un peor tiempo de bsqueda proporcional a la altura del rbol, esta cota superior de la altura permite a los rboles rojo-negro ser eficientes en el peor caso, de forma contraria a lo que sucede en los rboles binarios de bsqueda. Para ver que estas propiedades garantizan lo dicho, basta ver que ningn camino puede tener 2 nodos rojos seguidos debido a la propiedad 4. El camino ms corto posible tiene todos sus nodos negros, y el ms largo alterna entre nodos rojos y negros. Como todos los caminos mximos tienen el mismo nmero de nodos negros, por la propiedad 5, esto muestra que no hay ningn camino que pueda tener el doble de longitud que otro camino. En muchas presentaciones de estructuras arbreas de datos, es posible para un nodo tener solo un hijo y las hojas contienen informacin. Es posible presentar los rboles rojo-negro en este paradigma, pero cambian algunas de las propiedades y se complican los algoritmos. Por esta razn, este artculo utilizan hojas nulas, que no contienen informacin y simplemente sirven para indicar dnde el rbol acaba, como se mostr antes. Habitualmente estos nodos son omitidos en las representaciones, lo cual da como resultado un rbol que parece contradecir los principios expuestos antes, pero que realmente no los contradice. Como consecuencia de esto todos los nodos internos tienen dos hijos, aunque uno o ambos nodos podran ser una hoja nula. Otra explicacin que se da del rbol rojo-negro es la de tratarlo como un rbol binario de bsqueda cuyas aristas, en lugar de nodos, son coloreadas de color rojo o negro, pero esto no produce ninguna diferencia. El color de cada nodo en la terminologa de este artculo corresponde al color de la arista que une el nodo a su padre, excepto la raz, que es siempre negra (por la propiedad 2) donde la correspondiente arista no existe.

Usos y ventajas
Los rboles rojo-negro ofrecen un peor caso con tiempo garantizado para la insercin, el borrado y la bsqueda. No es esto nicamente lo que los hace valiosos en aplicaciones sensibles al tiempo como las aplicaciones en tiempo real, sino que adems son apreciados para la construccin de bloques en otras estructuras de datos que garantizan un peor caso. Por ejemplo, muchas estructuras de datos usadas en geometra computacional pueden basarse en rboles rojo-negro. El rbol AVL es otro tipo de estructura con O(log n) tiempo de bsqueda, insercin y borrado. Est equilibrado de forma ms rgida que los rboles rojo-negro, lo que provoca que la insercin y el borrado sean ms lentos pero la bsqueda y la devolucin del resultado de la misma ms veloz. Los rboles rojo-negro son particularmente valiosos en programacin funcional, donde son una de las estructuras de datos persistentes ms comnmente utilizadas en la construccin de arrays asociativos y conjuntos que pueden retener versiones previas tras mutaciones. La versin persistente del rbol rojo-negro requiere un espacio O(log n) para cada insercin o borrado, adems del tiempo. Los rboles rojo-negro son isomtricos a los rboles 2-3-4. En otras palabras, para cada rbol 2-3-4, existe un rbol correspondiente rojo-negro con los datos en el mismo orden. La insercin y el borrado en rboles 2-3-4 son tambin equivalentes a los cambios de colores y las rotaciones en los rboles rojo-negro. Esto los hace ser una herramienta til para la comprensin del funcionamiento de los rboles rojo-negro y por esto muchos textos introductorios sobre algoritmos presentan los rboles 2-3-4 justo antes que los rboles rojo-negro, aunque frecuentemente no sean utilizados en la prctica.

rbol rojo-negro

Operaciones
Las operaciones de slo lectura en un rbol rojo-negro no requieren modificacin alguna con respecto a las utilizadas en los rboles binarios de bsqueda, ya que cada rbol rojo-negro es un caso especial de rbol binario de bsqueda. Sin embargo, el resultado inmediato de una insercin o la eliminacin de un nodo utilizando los algoritmos de un rbol binario de bsqueda normal podra violar las propiedades de un rbol rojo-negro. Restaurar las propiedades rojo-negro requiere un pequeo nmero (O(log n))de cambios de color (que son muy rpidos en la prctica) y no ms de 3 rotaciones (2 por insercin). A pesar de que las operaciones de insercin y borrado son complicadas, sus tiempos de ejecucin siguen siendo O(log n).

Rotacin
Para conservar las propiedades que debe cumplir todo rbol rojo-negro, en ciertos casos de la insercin y la eliminacin ser necesario reestructurar el rbol, si bien no debe perderse la ordenacin relativa de los nodos. Para ello, se llevan a cabo una o varias rotaciones, que no son ms que reestructuraciones en las relaciones padre-hijo-to-nieto. Las rotaciones que se consideran a continuacin son simples; sin embargo, tambin se dan las rotaciones dobles. En las imgenes pueden verse de forma simplificada cmo se llevan a cabo las rotaciones simples hacia la izquierda y hacia la derecha en cualquier rbol binario de bsqueda, en particular en cualquier rbol rojo-negro. Podemos ver tambin la implementacin en C de dichas operaciones.

void rotar_izda(struct node *p) { struct node *aux; aux = p; p = p->dcho; aux-> dcho = p->izdo; p->izdo = aux; //reenraizar subarbol if(aux->padre->izdo == aux) aux->padre->izdo = p; else { // Aqui aux->padre->dcho == aux aux->padre->dcho = p;

rbol rojo-negro } // actualizar los padres de los nodos modificados p->padre = aux->padre; aux->padre = p; aux->dcho->padre = aux; // No hacer si usamos una sola hoja nula y aux->dcho es nulo }

void rotar_dcha(struct node *p) { struct node *aux; aux = p; p = p->izdo; aux->izdo = p->dcho; p->dcho = aux; // reenraizar subarbol if(aux->padre->izdo == aux) aux->padre->izdo = p; else { // aqui aux->padre->dcho == aux aux->padre->dcho = p; } // actualizar los padres de los nodos modificados p->padre = aux->padre; aux->padre = p; aux->izdo->padre = aux; // No hacer si usamos una sola hoja nula y aux->izdo es nulo }

rbol rojo-negro

Bsqueda
La bsqueda consiste acceder a la raz del rbol, si el elemento a localizar coincide con ste la bsqueda ha concluido con xito, si el elemento es menor se busca en el subrbol izquierdo y si es mayor en el derecho. Si se alcanza un nodo hoja y el elemento no ha sido encontrado se supone que no existe en el rbol. Cabe destacar que la bsqueda en este tipo de rboles es muy eficiente, representa una funcin logartmica. La bsqueda de un elemento en un ABB (rbol Binario de Bsqueda) en general, y en un rbol rojo negro en particular, se puede realizar de dos formas, iterativa o recursiva. Ejemplo de versin iterativa en el lenguaje de programacin C, suponiendo que estamos buscando una clave alojada en un nodo donde est el correspondiente "dato" que precisamos encontrar: data Buscar_ABB(abb t,clave k) { abb p; dato e; e=NULL; p=t; if (!estaVacio(p)) { while (!estaVacio(p) && (p->k!=k) ) { if (k < p->k) { p=p->l; } if (p->k < k) { p=p->r; } } if (!estaVacio(p) &&(p->d!=NULL) ) { e=copiaDato(p->d); } } return e; } Vase ahora la versin recursiva en ese mismo lenguaje: int buscar(tArbol *a, int elem) { if (a == NULL) return 0; else if (a->clave < elem) return buscar(a->hDerecho, elem); else if (a->clave > elem) return buscar(a->hIzquierdo, elem); else

rbol rojo-negro return 1; }

Insercin
La insercin comienza aadiendo el nodo como lo haramos en un rbol binario de bsqueda convencional y pintndolo de rojo. Lo que sucede despus depende del color de otros nodos cercanos. El trmino to nodo ser usado para referenciar al hermano del padre de un nodo, como en los rboles familiares humanos. Conviene notar que: La propiedad 3 (Todas las hojas, incluyendo las nulas, son negras) siempre se cumple. La propiedad 4 (Ambos hijos de cada nodo rojo son negros) est amenazada solo por aadir un nodo rojo, por repintar un nodo negro de color rojo o por una rotacin. La propiedad 5 (Todos los caminos desde un nodo dado hasta sus nodos hojas contiene el mismo nmero de nodos negros) est amenazada solo por repintar un nodo negro de color rojo o por una rotacin. Al contrario de lo que sucede en otros rboles como puede ser el rbol AVL, en cada insercin se realiza un mximo de una rotacin, ya sea simple o doble. Por otra parte, se asegura un tiempo de recoloracin mximo de por cada insercin. Nota: En los esquemas que acompaan a los algoritmos, la etiqueta N ser utilizada por el nodo que est siendo insertado, P para los padres del nodo N, G para los abuelos del nodo N, y U para los tos del nodo N. Notamos que los roles y etiquetas de los nodos estn intercambiados entre algunos casos, pero en cada caso, toda etiqueta contina representando el mismo nodo que representaba al comienzo del caso. Cualquier color mostrado en el diagrama est o bien supuesto en el caso o implicado por dichas suposiciones. Los nodos to y abuelo pueden ser encontrados por las siguientes funciones: struct node * abuelo(struct node *n) { if ((n != NULL) && (n->padre != NULL)) return n->padre->padre; else return NULL; } struct node * tio(struct node *n) { struct node *a = abuelo(n); if (n->padre == a->izdo) return a->dcho; else return a->izdo; } Estudiemos ahora cada caso de entre los posibles que nos podemos encontrar al insertar un nuevo nodo. Caso 1: El nuevo nodo N es la raz de del rbol. En este caso, es repintado a color negro para satisfacer la propiedad 2 (la raz es negra). Como esto aade un nodo negro a cada camino, la propiedad 5 (todos los caminos desde un nodo dado a sus hojas contiene el mismo nmero de nodos negros) se mantiene. En C quedara as:

rbol rojo-negro void insercion_caso1(struct node *n) { if (n->padre == NULL) n->color = NEGRO; else insercion_caso2(n); } Caso 2: El padre del nuevo nodo (esto es, el nodo P) es negro, as que la propiedad 4 (ambos hijos de cada nodo rojo son negros) se mantiene. En este caso, el rbol es aun vlido. La propiedad 5 (todos los caminos desde cualquier nodo dado a sus hojas contiene igual nmero de nodos negros) se mantiene, porque el nuevo nodo N tiene dos hojas negras como hijos, pero como N es rojo, los caminos a travs de cada uno de sus hijos tienen el mismo nmero de nodos negros que el camino hasta la hoja que reemplaz, que era negra, y as esta propiedad se mantiene satisfecha. Su implementacin: void insercion_caso2(struct node *n) { if (n->padre->color == NEGRO) return; /* rbol vlido. */ else insercion_caso3(n); } Nota: En los siguientes casos se puede asumir que N tiene un abuelo, el nodo G, porque su padre P es rojo, y si fuese la raz, sera negro. Consecuentemente, N tiene tambin un nodo to U a pesar de que podra ser una hoja en los casos 4 y 5.

Caso 3: Si el padre P y el to U son rojos, entonces ambos nodos pueden ser repintados de negro y el abuelo G se convierte en rojo para mantener la propiedad 5 (todos los caminos desde cualquier nodo dado hasta sus hojas contiene el mismo nmero de nodos negros). Ahora, el nuevo nodo rojo N tiene un padre negro. Como cualquier camino a travs del padre o el to debe pasar a travs del abuelo, el nmero de nodos negros en esos caminos no ha cambiado. Sin embargo, el abuelo G podra ahora violar la propiedad 2 (la raz es negra) o la 4 (ambos hijos de cada nodo rojo son negros), en el caso de la 4 porque G podra tener un padre rojo. Para solucionar este problema, el procedimiento completo se realizar de forma recursiva hacia arriba hasta alcanzar el caso 1. El cdigo en C quedara de la siguiente forma:

void insercion_caso3(struct node *n) { struct node *t = tio(n), *a; if ((t != NULL) && (t->color == ROJO)) { n->padre->color = NEGRO;

rbol rojo-negro t->color = NEGRO; a = abuelo(n); a->color = ROJO; insercion_caso1(a); } else { insercion_caso4(n); } } Nota: En los casos restantes, se asume que el nodo padre P es el hijo izquierdo de su padre. Si es el hijo derecho, izquierda y derecha deberan ser invertidas a partir de los casos 4 y 5. El cdigo del ejemplo toma esto en consideracin.

Caso 4: El nodo padre P es rojo pero el to U es negro; tambin, el nuevo nodo N es el hijo derecho de P, y P es el hijo izquierdo de su padre G. En este caso, una rotacin a la izquierda que cambia los roles del nuevo nodo N y su padre P puede ser realizada; entonces, el primer nodo padre P se ve implicado al usar el caso 5 de insercin (reetiquetando N y P ) debido a que la propiedad 4 (ambos hijos de cada nodo rojo son negros) se mantiene an incumplida. La rotacin causa que algunos caminos (en el sub-rbol etiquetado como 1) pasen a travs del nuevo nodo donde no lo hacan antes, pero ambos nodos son rojos, as que la propiedad 5 (todos los caminos desde cualquier nodo dado a sus hojas contiene el mismo nmero de nodos negros) no es violada por la rotacin. Aqu tenemos una posible implementacin:

void insercion_caso4(struct node *n) { struct node *a = abuelo(n); if ((n == n->padre->dcho) && (n->padre == a->izdo)) { rotar_izda(n->padre); n = n->izdo; } else if ((n == n->padre->izdo) && (n->padre == a->dcho)) { rotar_dcha(n->padre); n = n->dcho; } insercion_caso5(n); }

rbol rojo-negro

Caso 5: El padre P es rojo pero el to U es negro, el nuevo nodo N es el hijo izquierdo de P, y P es el hijo izquierdo de su padre G. En este caso, se realiza una rotacin a la derecha sobre el padre P; el resultado es un rbol donde el padre P es ahora el padre del nuevo nodo N y del inicial abuelo G. Este nodo G ha de ser negro, as como su hijo P rojo. Se intercambian los colores de ambos y el resultado satisface la propiedad 4 (ambos hijos de un nodo rojo son negros). La propiedad 5 (todos los caminos desde un nodo dado hasta sus hojas contienen el mismo nmero de nodos negros) tambin se mantiene satisfecha, ya que todos los caminos que iban a travs de esos tres nodos entraban por G antes, y ahora entran por P. En cada caso, este es el nico nodo negro de los tres. Una posible implementacin en C es la siguiente:

void insercion_caso5(struct node *n) { struct node *a = abuelo(n); n->padre->color = NEGRO; a->color = ROJO; if ((n == n->padre->izdo) && (n->padre == a->izdo)) { rotar_dcha(a); } else { /* * En este caso, (n == n->padre->dcho) && (n->padre == a->dcho). */ rotar_izda(a); } } Ntese que la insercin se realiza sobre el propio rbol y que los cdigos del ejemplo utilizan recursin de cola.

Eliminacin
En un rbol binario de bsqueda normal, cuando se borra un nodo con dos nodos internos como hijos, tomamos el mximo elemento del subrbol izquierdo o el mnimo del subrbol derecho, y movemos su valor al nodo que es borrado (como se muestra aqu). Borramos entonces el nodo del que copibamos el valor que debe tener menos de dos nodos no hojas por hijos. Copiar un valor no viola ninguna de las propiedades rojo-negro y reduce el problema de borrar en general al de borrar un nodo con como mucho un hijo no hoja. No importa si este nodo es el nodo que queramos originalmente borrar o el nodo del que copiamos el valor. Resumiendo, podemos asumir que borramos un nodo con como mucho un hijo no hoja (si solo tiene nodos hojas por hijos, tomaremos uno de ellos como su hijo). Si borramos un nodo rojo, podemos simplemente reemplazarlo con su hijo, que debe ser negro. Todos los caminos hasta el nodo borrado simplemente pasarn a travs de un nodo rojo menos, y ambos nodos, el padre del borrado y el hijo, han de ser negros, as que las propiedades 3 (todas las hojas, incluyendo las nulas, son negras) y 4 (los dos hijos de cada nodo rojo son negros) se mantienen. Otro caso simple es cuando el nodo borrado es negro y su hijo es rojo. Simplemente eliminar un nodo negro podra romper las

rbol rojo-negro propiedades 4 (los dos hijos de cada nodo rojo son negros) y 5 (todos los caminos desde un nodo dado hasta sus hojas contienen el mismo nmero de nodos negros), pero si repintamos su hijo de negro, ambas propiedades quedan preservadas. El caso complejo es cuando el nodo que va a ser borrado y su hijo son negros. Empezamos por reemplazar el nodo que va a ser borrado con su hijo. Llamaremos a este hijo (en su nueva posicin) N, y su hermano (el otro hijo de su nuevo padre) S. En los diagramas de debajo, usaremos P para el nuevo padre de N, SL para el hijo izquierdo de S, y SR para el nuevo hijo derecho de S (se puede mostrar que S no puede ser una hoja). Nota: Entre algunos casos cambiamos roles y etiquetas de los nodos, pero en cada caso, toda etiqueta sigue representando al mismo nodo que representaba al comienzo del caso. Cualquier color mostrado en el diagrama es o bien supuesto en su caso o bien implicado por dichas suposiciones. El blanco representa un color desconocido (o bien rojo o bien negro). El cumplimiento de estas reglas en un rbol con n nodos, asegura un mximo de tres rotaciones y hasta recoloraciones. Encontraremos el hermano usando esta funcin: struct node * hermano(struct node *n) { if (n == n->padre->izdo) return n->padre->dcho; else return n->padre->izdo; } Nota: Con el fin de preservar la buena definicin del rbol, necesitamos que toda hoja nula siga siendo una hoja nula tras todas las transformaciones (que toda hoja nula no tendr ningn hijo). Si el nodo que estamos borrando tiene un hijo no hoja N, es fcil ver que la propiedad se satisface. Si, por otra parte N fuese una hoja nula, se verifica por los diagramas o el cdigo que para todos los casos la propiedad se satisface tambin. Podemos realizar los pasos resaltados arriba con el siguiente cdigo, donde la funcin reemplazar_nodo sustituye hijo en el lugar de n en el rbol. Por facilitar la comprensin del ejemplo, en el cdigo de esta seccin supondremos que las hojas nulas estn representadas por nodos reales en lugar de NULL (el cdigo de la seccin insercin trabaja con ambas representaciones). void elimina_un_hijo(struct node *n) { /* * Precondicin: n tiene al menos un hijo no nulo. */ struct node *hijo = es_hoja(n->dcho) ? n->izdo : n->dcho; reemplazar_nodo(n, hijo); if (n->color == NEGRO) { if (hijo->color == ROJO) hijo->color = NEGRO; else eliminar_caso1(hijo); }

10

rbol rojo-negro free(n); } Nota: Si N es una hoja nula y no queremos representar hojas nulas como nodos reales, podemos modificar el algoritmo llamando primero a eliminar_caso1() en su padre (el nodo que borramos, n en el cdigo anterior) y borrndolo despus. Podemos hacer esto porque el padre es negro, as que se comporta de la misma forma que una hoja nula (y a veces es llamada hoja fantasma). Y podemos borrarla con seguridad, de tal forma que n seguir siendo una hoja tras todas las operaciones, como se muestra arriba. Si N y su padre original son negros, entonces borrar este padre original causa caminos que pasan por N y tienen un nodo negro menos que los caminos que no. Como esto viola la propiedad 5 (todos los caminos desde un nodo dado hasta su nodos hojas deben contener el mismo nmero de nodos negros), el rbol debe ser reequilibrado. Hay varios casos a considerar. Caso 1: N es la nueva raz. En este caso, hemos acabado. Borramos un nodo negro de cada camino y la nueva raz es negra, as las propiedades se cumplen. Una posible implementacin en el lenguaje de programacin C sera la siguiente: void eliminar_caso1(struct node *n) { if (n->padre!= NULL) eliminar_caso2(n); } Nota: En los casos 2, 5 y 6, asumimos que N es el hijo izquierdo de su padre P. Si ste fuese el hijo derecho, la izquierda y la derecha deberan ser invertidas en todos estos casos. De nuevo, el cdigo del ejemplo toma ambos casos en cuenta.

11

Caso 2: S es rojo. En este caso invertimos los colores de P y S, por lo que rotamos a la izquierda P, pasando S a ser el abuelo de N. Ntese que P tiene que ser negro al tener un hijo rojo. Aunque todos los caminos tienen todava el mismo nmero de nodos negros, ahora N tiene un hermano negro y un padre rojo, as que podemos proceder a al paso 4, 5 o 6 (este nuevo hermano es negro porque ste era uno de los hijos de S, que es rojo). En casos posteriores, reetiquetaremos el nuevo hermano de N como S. Aqu podemos ver una implementacin:

void eliminar_caso2(struct node *n) { struct node *hm = hermano(n); if (hm->color == ROJO) { n->padre->color = ROJO; hm->color = NEGRO; if (n == n->padre->izdo) rotar_izda(n->padre); else

rbol rojo-negro rotar_dcha(n->padre); } eliminar_caso3(n); }

12

Caso 3: P, S y los hijos de S son negros. En este caso, simplemente cambiamos S a rojo. El resultado es que todos los caminos a travs de S, precisamente aquellos que no pasan por N, tienen un nodo negro menos. El hecho de borrar el padre original de N haciendo que todos los caminos que pasan por N tengan un nodo negro menos nivela el rbol. Sin embargo, todos los caminos a travs de P tienen ahora un nodo negro menos que los caminos que no pasan por P, as que la propiedad 5 an no se cumple (todos los caminos desde cualquier nodo a su nodo hijo contienen el mismo nmero de nodos negros). Para corregir esto, hacemos el proceso de reequilibrio en P, empezando en el caso 1. Su implementacin en C:

void eliminar_caso3(struct node *n) { struct node *hm = hermano_menor(n); if ((n->padre->color == NEGRO) && (hm->color == NEGRO) && (hm->izdo->color == NEGRO) && (hm->dcho->color == NEGRO)) { hm->color = ROJO; eliminar_caso1(n->padre); } else eliminar_caso4(n); }

Caso 4: S y los hijos de ste son negros, pero P es rojo. En este caso, simplemente intercambiamos los colores de S y P. Esto no afecta al nmero de nodos negros en los caminos que no van a travs de S, pero aade uno al nmero de nodos negros a los caminos que van a travs de N, compensando as el borrado del nodo negro en dichos caminos. Si lo implementamos en C, quedara:

void eliminar_caso4(struct node *n) { struct node *hm = hermano_menor(n);

rbol rojo-negro if ((n->padre->color == ROJO) && (hm->color == NEGRO) && (hm->izdo->color == NEGRO) && (hm->dcho->color == NEGRO)) { hm->color = ROJO; n->padre->color = NEGRO; } else eliminar_caso5(n); }

13

Caso 5: S es negro, su hijo izquierdo es rojo, el derecho es negro, y N es el hijo izquierdo de su padre. En este caso rotamos a la derecha S, as su hijo izquierdo se convierte en su padre y en el hermano de N. Entonces intercambiamos los colores de S y su nuevo padre. Todos los caminos tienen an el mismo nmero de nodos negros, pero ahora N tiene un hermano negro cuyo hijo derecho es rojo, as que caemos en el caso 6. Ni N ni su padre son afectados por esta transformacin (de nuevo, por el caso 6, reetiquetamos el nuevo hermano de N como S). He aqu la implementacin en C:

void eliminar_caso5(struct node *n) { struct node *hm = hermano(n); if ((n == n->padre->izdo) && (hm->color == NEGRO) && (hm->izdo->color == ROJO) && (hm->dcho->color == NEGRO)) { hm->color = ROJO; hm->izdo->color = NEGRO; rotar_dcha(hm); } else if ((n == n->padre->dcho) && (hm->color == NEGRO) && (hm->dcho->color == ROJO) && (hm->izdo->color == NEGRO)) { hm->color = ROJO; hm->dcho->color = NEGRO; rotar_izda(hm); } eliminar_caso6(n); }

rbol rojo-negro

14

Caso 6: S es negro, su hijo derecho es rojo, y N es el hijo izquierdo de P, su padre. En este caso rotamos a la izquierda P, as que S se convierte en el padre de P y ste en el hijo derecho de S. Entonces intercambiamos los colores de P y S, y ponemos el hijo derecho de S en negro. El subrbol an tiene el mismo color que su raz, as que las propiedades 4 (los hijos de todo nodo rojo son negros) y 5 (todos los caminos desde cualquier nodo a sus nodos hoja contienen el mismo nmero de nodos negros) se verifican. Sin embargo, N tiene ahora un antecesor negro mas: o bien P se ha convertido en negro, o bien era negro y S se ha aadido como un abuelo negro. De este modo, los caminos que pasan por N pasan por un nodo negro mas. Mientras tanto, si un camino no pasa por N, entonces hay dos posibilidades: ste pasa a travs del nuevo hermano de N. Entonces, ste debe pasar por S y P, al igual que antes, y tienen slo que intercambiar los colores. As los caminos contienen el mismo nmero de nodos negros. ste pasa por el nuevo to de N, el hijo derecho de S. ste anteriormente pasaba por S, su padre y su hijo derecho, pero ahora slo pasa por S, el cual ha tomado el color de su anterior padre, y por su hijo derecho, el cual ha cambiado de rojo a negro. El efecto final es que este camino va por el mismo nmero de nodos negros.

De cualquier forma, el nmero de nodos negros en dichos caminos no cambia. De este modo, hemos restablecido las propiedades 4 (los hijos de todo nodo rojo son negros) y 5 (todos los caminos desde cualquier nodo a sus nodos hoja contienen el mismo nmero de nodos negros). El nodo blanco en diagrama puede ser rojo o negro, pero debe tener el mismo color tanto antes como despus de la transformacin. Adjuntamos el ltimo algoritmo:

void eliminar_caso6(struct node *n) { struct node *hm = hermano(n); hm->color = n->padre->color; n->padre->color = NEGRO; if (n == n->padre->izdo) { /* * Aqu, hm->dcho->color == ROJO. */ hm->dcho->color = NEGRO; rotar_izda(n->padre); } else { /* * Aqu, hm->izdo->color == ROJO. */ hm->izdo->color = NEGRO; rotar_dcha(n->padre); } } De nuevo, todas las llamadas de la funcin usan recursin de cola as que el algoritmo realiza sus operaciones sobre el propio rbol. Adems, las llamadas no recursivas se harn despus de una rotacin, luego se harn un nmero de rotaciones (ms de 3) que ser constante.

rbol rojo-negro

15

Demostracin de cotas
Un rbol rojo-negro que contiene n nodos internos tiene una altura de O(log(n)). Hagamos los siguientes apuntes sobre notacin: H(v) = altura del rbol cuya raz es el nodo v. bh(v) = nmero de nodos negros (sin contar v si es negro) desde v hasta cualquier hoja del subrbol (llamado altura-negra). Lema: Un subrbol enraizado al nodo v tiene al menos Demostracin del lema (por induccin sobre la altura): Caso base: h(v)=0 Si v tiene altura cero entonces debe ser rbol vaco, por tanto bh(v)=0. Luego: nodos internos.

Hiptesis de Induccin: si v es tal que h(v) = k y contiene

nodos internos, veamos que esto implica que )o

tal que h( ) = k+1 contiene nodos internos. Si tiene h( ) > 0 entonces es un nodo interno. Como ste tiene dos hijos que tienen altura-negra, o bh( bh( )-1 (dependiendo si es rojo o negro). Por la hiptesis de induccin cada hijo tiene al menos

nodos internos, as que tiene : nodos internos. Usando este lema podemos mostrar que la altura del rbol es algortmica. Puesto que al menos la mitad de los nodos en cualquier camino desde la raz hasta una hoja negra (propiedad 4 de un rbol rojo-negro), la altura-negra de la raz es al menos h(raz)/2. Por el lema tenemos que:

Por tanto, la altura de la raz es O(log(n)).

Complejidad
En el cdigo del rbol hay un bucle donde la raz de la propiedad rojo-negro que hemos querido devolver a su lugar, x, puede ascender por el rbol un nivel en cada iteracin Como la altura original del rbol es O(log n), hay O(log n) iteraciones. As que en general la insercin tiene una complejidad de O(log n).

Referencias
Hernndez, Zenn; Rodrguez, J.Carlos; Gonzlez, J.Daniel; Daz, Margarita; Prez, Jos; Rodrguez, Gustavo. (2005). Fundamentos de Estructuras de Datos. Soluciones en Ada, Java y C++.. Madrid: Thomson Editores Spain. 84-9732-358-0. Mathworld: Red-Black Tree [1]. San Diego State University: CS 660: Red-Black tree notes [2], by Roger Whitney. Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein. Introduction to Algorithms, Second Edition. MIT Press and McGraw-Hill, 2001. ISBN 0-262-03293-7 . Chapter 13: Red-Black Trees, pp.273301. Pfaff, Ben (June de 2004). Performance Analysis of BSTs in System Software [3] (PDF). Stanford_university.. Okasaki, Chris. Red-Black Trees in a Functional Setting [4] (PS)..

rbol rojo-negro

16

Enlaces externos
Demos y simuladores
Simulador de rboles Rojo-Negro [5]. Red Black Tree Applet [6], una demo de los rboles rojo-negro y otros muchos ms rboles de bsqueda, por Kubo Kovac. Red Black Tree Applet [7], una demo de los rboles rojo-negro, AVL, rotaciones y mucho ms. Red/Black Tree Demonstration [8], una demo interactiva acerca de la insercin y eliminacin con una implementacin en Java. Red-Black Tree Animation [9], una demostracin de la insercin en el peor caso. aiSee: Visualization of a Sorting Algorithm [10], GIF animado que muestra la insercin (200KB). Red-Black Tree Demonstration [11], una demo acerca de la insercin, en cdigo Java, por David M. Howard. AVL Tree Applet [7], una demo interactiva acercad de la insercin y la eliminaicn en rboles AVL, splay y rojo-negro.

Implementaciones
Descargar Programa Red-black [12] en java. En la librera de C++, Standard Template Library, los containers std::set<Value> y std::map<Key,Value> estn implementados a menudo con rboles rojo-negro. Implementacin eficiente de rboles rojo-negro. [13] RBT: Una biblioteca de rboles rojo-negro en SmallEiffel. [14] libredblack: Una biblioteca de rboles rojo-negro en C. [15] Cdigo en C de rboles rojo-negro. [16] Implementacin en Java de os rboles rojo-negro en java.util.TreeMap [17] Los subsistemas de DragonFlyBSD VM utilizan rboles rojo-negro. [18] NATURAL/ADABAS implementacin de Paul Macgowan [19] NGenerics : implementacin en C# [20] FreeBSD's single header file implementation [21] The default scheduler of Linux 2.6.23, called Completely Fair Scheduler, is implemented via a Red-Black tree [22]

Referencias
[1] http:/ / mathworld. wolfram. com/ Red-BlackTree. html [2] http:/ / www. eli. sdsu. edu/ courses/ fall95/ cs660/ notes/ RedBlackTree/ RedBlack. html#RTFToC2 [3] http:/ / www. stanford. edu/ ~blp/ papers/ libavl. pdf [4] http:/ / www. eecs. usma. edu/ webs/ people/ okasaki/ jfp99. ps [5] https:/ / www. gedlc. ulpgc. es/ docencia/ ed_ii/ simulaciones/ arboles_binarios/ applet. html [6] http:/ / people. ksp. sk/ ~kuko/ bak/ index. html [7] http:/ / webpages. ull. es/ users/ jriera/ Docencia/ AVL/ AVL%20tree%20applet. htm [8] http:/ / www. ececs. uc. edu/ ~franco/ C321/ html/ RedBlack/ redblack. html [9] http:/ / www. ibr. cs. tu-bs. de/ lehre/ ss98/ audii/ applets/ BST/ RedBlackTree-Example. html [10] http:/ / www. aisee. com/ anim/ maple. htm [11] http:/ / geocities. com/ dmh2000/ articles/ code/ red-blacktree. html [12] http:/ / miarroba. com/ foros/ ver. php?foroid=674005& temaid=3112672 [13] http:/ / eternallyconfuzzled. com/ tuts/ datastructures/ jsw_tut_rbtree. aspx [14] http:/ / efsa. sourceforge. net/ archive/ durian/ red_black_tree. htm [15] http:/ / libredblack. sourceforge. net/ [16] http:/ / web. mit. edu/ ~emin/ www/ source_code/ red_black_tree/ index. html [17] http:/ / www. javaresearch. org/ source/ jdk142/ java/ util/ TreeMap. java. html [18] http:/ / dragonflybsd. org [19] http:/ / scctoolkit. atspace. com

rbol rojo-negro
[20] http:/ / www. codeplex. com/ NGenerics [21] http:/ / fxr. watson. org/ fxr/ source/ / sys/ tree. h [22] http:/ / www. ibm. com/ developerworks/ linux/ library/ l-cfs/ ?ca=dgr-lnxw04CFC4Linux

17

Fuentes y contribuyentes del artculo

18

Fuentes y contribuyentes del artculo


rbol rojo-negro Fuente: http://es.wikipedia.org/w/index.php?oldid=58487543 Contribuyentes: Amanuense, Ascnder, Bermudob, Carutsu, Cburnett, Ender., Gramito, Isha, Lasneyx, Mariols15, Matdrodes, Periku, Petnapet, Porao, Regnaron, Sabbut, Tomatejc, U.gonzalez, Vcarceler, Wmtnez, 44 ediciones annimas

Fuentes de imagen, Licencias y contribuyentes


Archivo:Red-black tree example.svg Fuente: http://es.wikipedia.org/w/index.php?title=Archivo:Red-black_tree_example.svg Licencia: Creative Commons Attribution-ShareAlike 3.0 Unported Contribuyentes: en:User:Cburnett Archivo:Rotacin_Simple_izquierda.JPG Fuente: http://es.wikipedia.org/w/index.php?title=Archivo:Rotacin_Simple_izquierda.JPG Licencia: Creative Commons Attribution-Share Alike Contribuyentes: Jose Mara Garca Alaminos Archivo:Rotacin_Simple_derecha.JPG Fuente: http://es.wikipedia.org/w/index.php?title=Archivo:Rotacin_Simple_derecha.JPG Licencia: Public Domain Contribuyentes: Jose Mara Garca Alaminos Archivo:Red-black_tree_insert_case_3.png Fuente: http://es.wikipedia.org/w/index.php?title=Archivo:Red-black_tree_insert_case_3.png Licencia: Public Domain Contribuyentes: Users Cintrom, Deco, Deelkar on en.wikipedia Archivo:Red-black_tree_insert_case_4.png Fuente: http://es.wikipedia.org/w/index.php?title=Archivo:Red-black_tree_insert_case_4.png Licencia: Public Domain Contribuyentes: User Deco on en.wikipedia Archivo:Red-black_tree_insert_case_5.png Fuente: http://es.wikipedia.org/w/index.php?title=Archivo:Red-black_tree_insert_case_5.png Licencia: Public Domain Contribuyentes: User Deco on en.wikipedia Archivo:Red-black_tree_delete_case_2.png Fuente: http://es.wikipedia.org/w/index.php?title=Archivo:Red-black_tree_delete_case_2.png Licencia: Public Domain Contribuyentes: Users Deelkar, Deco on en.wikipedia Archivo:Red-black_tree_delete_case_3.png Fuente: http://es.wikipedia.org/w/index.php?title=Archivo:Red-black_tree_delete_case_3.png Licencia: Public Domain Contribuyentes: User Deco on en.wikipedia Archivo:Red-black_tree_delete_case_4.png Fuente: http://es.wikipedia.org/w/index.php?title=Archivo:Red-black_tree_delete_case_4.png Licencia: Public Domain Contribuyentes: User Deco on en.wikipedia Archivo:Red-black_tree_delete_case_5.png Fuente: http://es.wikipedia.org/w/index.php?title=Archivo:Red-black_tree_delete_case_5.png Licencia: Public Domain Contribuyentes: User Deco on en.wikipedia Archivo:Red-black_tree_delete_case_6.png Fuente: http://es.wikipedia.org/w/index.php?title=Archivo:Red-black_tree_delete_case_6.png Licencia: Public Domain Contribuyentes: User Deco on en.wikipedia

Licencia
Creative Commons Attribution-Share Alike 3.0 Unported //creativecommons.org/licenses/by-sa/3.0/

You might also like