Estructura de Un Arbol
Estructura de Un Arbol
Estructura de Un Arbol
Pgina 1 de 91
ESTRUCTURA DE RBOLES
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Pgina 3 de 91
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
rboles binarios
Tipos de rboles binarios
Un rbol binario es una estructura de datos de tipo rbol en donde cada uno
de los nodos del rbol puede tener 0, 1, 2 subrboles llamados de acuerdo
a su caso como:
Si el nodo raz tiene 0 relaciones se llama hoja.
Si el nodo raz tiene 1 relacin a la izquierda, el segundo elemento de
la relacin es el subrbol izquierdo.
Si el nodo raz tiene 1 relacin a la derecha, el segundo elemento de la
relacin es el subrbol derecho.
Existen dos tipos de rboles binarios que se consideran especiales en funcin
de ciertas propiedades.
Estos son los siguientes:
1. rbol binario equilibrado
2. rbol binario completo
1. rbol binario equilibrado
Es un rbol en el que en todos sus nodos se cumple la siguiente propiedad:
Pgina 5 de 91
Recorrido Pre-orden (N I D)
En este recorrido lo primero que se obtiene o evala es el nodo, antes de
recorrer las ramas; posteriormente se recorre la rama izquierda y finalmente
la rama derecha. El orden es Nodo Izquierda Derecha (N I D).
El recorrido Pre-orden de nuestro rbol de la Figura 3 es: M E A R O
NQV
Y el recorrido Pre-orden del rbol de la Figura 5 es: N E A G R O V
Recorrido In-orden (I N D)
En este recorrido se procesa la primera rama (rama izquierda), despus el
nodo y finalmente la ultima rama (rama derecha). El orden es: Izquierda
Nodo Derecha (I N D).
El recorrido In-orden de nuestro rbol de la Figura 3 es: A E M N O
QRV
Y el recorrido In-orden del rbol de la Figura 5 es: A E G N O R V
Recorrido Post-orden (I D R)
En este recorrido se primero se procesan las ramas para finalmente procesar
el nodo. El orden de este recorrido es: Izquierda Derecha Nodo (I D
N).
El recorrido Post-orden del rbol de la Figura 3 es: A E N Q O V R
M
Y el recorrido Post-orden del rbol de la Figura 5 es: A G E O V R
N
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Grficamente.
Pgina 7 de 91
Implementacin en C++
//Este programa permite generar nmeros aleatorios y los
inserta en un rbol binario adems de obtener los niveles
mximos y mnimo saca la diferencia de estos mismos y me
dice cuantas veces.
#include<stdlib.h>
#include<stdio.h>
#include<conio.h>
#include<iostream.h>
#include<dos.h>
#define VERDADERO 1
#define FALSO 0
#define VECES 50
efecta la operacin
#define cant_num 100
tendr el rbol
#define RANGO 1000
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Inserta(x,&((*t)->izq));
else
Inserta(x,&((*t)->der));
}
int nivel_mayor(ABB p)
{
if(p==NULL) return 0;
else
{
int nivelI=nivel_mayor(p->izq);
int nivelD=nivel_mayor(p->der);
if (nivelI>nivelD) return nivelI+1;
else
return nivelD+1;
}
}
int nivel_menor(ABB p)
{
if(p==NULL) return 0;
else
{
int nivelI=nivel_menor(p->izq);
int nivelD=nivel_menor(p->der);
if (nivelI<nivelD) return nivelI+1;
else
return nivelD+1;
}
}
void main()
{
int res;
int arr[VECES];
int num;
int alto[50];
int bajo[50];
ABB raiz;
randomize();
for(int CONT1=1;CONT1<=VECES;CONT1++)
{
clrscr();
cout<<" LOS NUMEROS INSERTADOS EN EL ARBOL
SON..."<<endl;
for(int CONT2=1;CONT2<=cant_num;CONT2++)
{
num=random(RANGO);
//genero el numero aleatorio
cout<<num<<"\t";
if(CONT2>1) Inserta(num,&raiz);
else
raiz=Crear(num);
}
alto[CONT1]=nivel_mayor(raiz);
Pgina 9 de 91
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
<stdio.h>
<conio.h>
<alloc.h>
<process.h>
struct Arbol{
int Dato;
struct Arbol *Izq;
struct Arbol *Der;
};
struct Arbol *ConstruirArbol(int);
void ImprimeArbol(struct Arbol *,int);
void Error();
int main(void)
{
int nodos;
struct Arbol *Raiz;
system("cls");
printf("Numero de nodos: ");
scanf("%d",&nodos);
printf("\nIntroduce los datos.\n\n");
Raiz=ConstruirArbol(nodos);
printf("\nImpresion del Arbol.\n\n");
ImprimeArbol(Raiz,0);
getch();
return 0;
}
void Error(void)
{
perror("error: No hay memoria.\n");
getch();
abort();
}
struct Arbol *NuevoNodo(void)
{
struct Arbol *Raiz=(struct Arbol
*)malloc(sizeof(struct Arbol));
if(!Raiz) Error();
return Raiz;
}
struct Arbol *ConstruirArbol(int nodos)
{
struct Arbol *Raiz;
int Ni,Nd;
if(nodos==0)
return NULL;
Pgina 11 de 91
else{
Ni=nodos/2;
Nd=nodos-Ni-1;
Raiz=NuevoNodo();
printf("Dato-> ");
scanf("%d",&Raiz->Dato);
Raiz->Izq=ConstruirArbol(Ni);
Raiz->Der=ConstruirArbol(Nd);
return Raiz;
}
}
void ImprimeArbol(struct Arbol *Raiz,int n)
{
int i;
if(Raiz==NULL) return;
ImprimeArbol(Raiz->Izq,n+1);
for(i=0;i<n;i++)
printf(" ");
printf("%d\n",Raiz->Dato);
ImprimeArbol(Raiz->Der,n+1);
}
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Implementacin en Java
//Programa que permite crear un arbol binario y hacer sus respectivos
recorridos
Clase Nodo binario
static int size (NodoB a){...;}
static int height (NodoB a){...;}
void preorder (NodoB a){...;}
void inorder (NodoB a){...;}
void postorder (NodoB a){...;}
//Clase rbol binario...
class ArbolB {
protected NodoB raiz;
ArbolB() {raiz=null;}
ArbolB(Object o){raiz=new NodoB(o);}
public int size()
{return NodoB.size(raiz);}
public int height()
{return NodoB.height(raiz);}
public void preorder ()
{if (raiz!=null) raiz.preorder();}
public void inorder ()
{if (raiz!=null) raiz.inorder();}
public void postorder ()
{if (raiz!=null) raiz.postorder();}
}
// Tamao
static int size (NodoB a){
if (a==null)
return 0;
else
return 1+size(a.izq)+size(a.der);
}
// Altura
static int height (NodoB a){
if (a==null)
return (-1);
else
return 1+Math.max(height(a.izq),
height(a.der));
}
//RECORRIDOS
Pgina 13 de 91
// preorden
void preorder (){
System.out.println(d);
if (izq != null)
izq.preorder();
if (der != null)
der.preorder();
}
//postorden
void postorder (){
if (izq != null)
izq.postorder();
if (der != null)
der.postorder();
System.out.println(d);
}
// inorden
void inorder (){
if (izq != null)
izq.inorder();
System.out.println(d);
if (der != null)
der.inorder();
}
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Pgina 15 de 91
Operaciones en ABB
El repertorio de operaciones que se pueden realizar sobre un ABB es parecido
al que realizbamos sobre otras estructuras de datos, ms alguna otra propia
de rboles:
Buscar un elemento.
Insertar un elemento.
Borrar un elemento.
Movimientos a travs del rbol:
o Izquierda.
o Derecha.
o Raz.
Informacin:
o Comprobar si un rbol est vaco.
o Calcular el nmero de nodos.
o Comprobar si el nodo es hoja.
o Calcular la altura de un nodo.
o Calcular la altura de un rbol.
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Buscar un elemento.
Partiendo siempre del nodo raz, el modo de buscar un elemento se define de
forma recursiva.
Si el rbol est vaco, terminamos la bsqueda: el elemento no est en
el rbol.
Si el valor del nodo raz es igual que el del elemento que buscamos,
terminamos la bsqueda con xito.
Si el valor del nodo raz es mayor que el elemento que buscamos,
continuaremos la bsqueda en el rbol izquierdo.
Si el valor del nodo raz es menor que el elemento que buscamos,
continuaremos la bsqueda en el rbol derecho.
El valor de retorno de una funcin de bsqueda en un ABB puede ser un
puntero al nodo encontrado, o NULL, si no se ha encontrado.
Insertar un elemento
Para insertar un elemento nos basamos en el algoritmo de bsqueda. Si el
elemento est en el rbol no lo insertaremos. Si no lo est, lo insertaremos a
continuacin del ltimo nodo visitado.
Necesitamos un puntero auxiliar para conservar una referencia al padre del
nodo raz actual. El valor inicial para ese puntero es NULL.
Padre = NULL
nodo = Raiz
Bucle: mientras actual no sea un rbol vaco o hasta que se
encuentre el elemento.
o Si el valor del nodo raz es mayor que el elemento que
buscamos, continuaremos la bsqueda en el rbol
izquierdo: Padre=nodo, nodo=nodo->izquierdo.
o Si el valor del nodo raz es menor que el elemento que
buscamos, continuaremos la bsqueda en el rbol derecho:
Padre=nodo, nodo=nodo->derecho.
Si nodo no es NULL, el elemento est en el rbol, por lo tanto
salimos.
Si Padre es NULL, el rbol estaba vaco, por lo tanto, el nuevo
rbol slo contendr el nuevo elemento, que ser la raz del rbol.
Si el elemento es menor que el Padre, entonces insertamos el
nuevo elemento como un nuevo rbol izquierdo de Padre.
Si el elemento es mayor que el Padre, entonces insertamos el
nuevo elemento como un nuevo rbol derecho de Padre.
Este modo de actuar asegura que el rbol sigue siendo ABB.
Pgina 17 de 91
Borrar un elemento
Para borrar un elemento tambin nos basamos en el algoritmo de bsqueda.
Si el elemento no est en el rbol no lo podremos borrar. Si est, hay dos
casos posibles:
1. Se trata de un nodo hoja: en ese caso lo borraremos directamente.
2. Se trata de un nodo rama: en ese caso no podemos eliminarlo, puesto
que perderamos todos los elementos del rbol de que el nodo actual
es padre. En su lugar buscamos el nodo ms a la izquierda del
subrbol derecho, o el ms a la derecha del subrbol izquierdo e
intercambiamos sus valores. A continuacin eliminamos el nodo hoja.
Necesitamos un puntero auxiliar para conservar una referencia al padre del
nodo raz actual. El valor inicial para ese puntero es NULL.
Si se espera que el nmero de eliminaciones sea pequeo, la
eliminacin perezosa es una buena estrategia. Al eliminar un
elemento, se deja en el rbol marcndolo como eliminado. Habiendo
claves duplicadas, es posible decrementar el campo con la
frecuencia de apariciones. Si una clave eliminada se vuelve a
insertar, se evita la sobrecarga de asignar un nodo nuevo.
Si el nmero de nodos reales en el rbol es igual al nmero de
nodos eliminados, se espera que la profundidad del rbol solo
aumente en uno (por qu?).
o La penalizacin de tiempo es pequea.
Recorridos de un rbol
Las versiones recursivas de los recorridos son costosas debido a la gran
cantidad de llamadas recursivas que pueden llegar a copar la pila (stack)
Se prefieren entonces versiones no recursivas para dichos recorridos
Las versiones no recursivas de estos recorridos requieren el uso de
un arreglo (o lista) auxiliar de apuntadores a los nodos.
Su codificacin es menos clara que sus versiones recursivas
En orden: Se procesa el subrbol izquierdo, el nodo actual y, por ultimo, el
subrbol derecho. O(n)
Post-orden: Ambos subrboles primero. O(n)
Pre-orden: El nodo se procesa antes. Ej.: una funcin que marcase cada
nodo con su profundidad. O(n)
Orden de nivel: Todos los nodos con profundidad p se procesan antes que
cualquier nodo con profundidad p+1.
Se usa una cola en vez de la pila implcita en la recursin. O(n)
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Pgina 19 de 91
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Implementacin en C++
//El siguiente cdigo en lenguaje C muestra cmo realizar
una bsqueda en un ABB
//Buscar
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
return 1;
}
data abb_search(abb t,key k) {
abb p;
data e;
e=NULL;
p=t;
if (!abb_isEmpty(p))
{
while (!abb_isEmpty(p) && (p->k!=k) )
{
if (k < p->k)
{
p=p->l;
}
if (p->k < k)
{
p=p->r;
}
}
if (!abb_isEmpty(p) &&(p->d!=NULL) )
{
e=data_copy(p->d);
}
}
return e;
}
//Insertar
void insertar(tArbol **a, int elem)
{
if (*a == NULL)
{
Pgina 21 de 91
*a = (tArbol *) malloc(sizeof(tArbol));
(*a)->clave = elem;
(*a)->hIzquierdo = NULL;
(*a)->hDerecho = NULL;
}
else if ((*a)->clave < elem)
insertar(&(*a)->hDerecho, elem);
else if ((*a)->clave > elem)
insertar(&(*a)->hIzquierdo, elem);
}
//Borrado
void borrar(tArbol **a, int elem)
{
void reemplazar(tArbol **a, tArbol **aux);
tArbol *aux;
if (*a == NULL)
return;
if ((*a)->clave < elem)
borrar(&(*a)->hDerecho, elem);
else if ((*a)->clave > elem)
borrar(&(*a)->hIzquierdo, elem);
else if ((*a)->clave == elem)
{
aux = *a;
if ((*a)->hIzquierdo == NULL)
*a = (*a)->hDerecho;
else if ((*a)->hDerecho == NULL)
*a = (*a)->hIzquierdo;
else
reemplazar(&(*a)->hIzquierdo, &aux);
free(aux);
}
}
void reemplazar(tArbol **a, tArbol **aux)
{
if ((*a)->hDerecho == NULL)
{
(*aux)->clave = (*a)->clave;
*aux = *a;
*a = (*a)->hIzquierdo;
}
else
reemplazar(&(*a)->hDerecho, aux);
}
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
//ABB
#include <iostream>
using namespace std;
class ArbolABB {
private:
//// Clase local de Lista para Nodo de ArbolBinario:
class Nodo {
public:
// Constructor:
Nodo(const int dat, Nodo *izq=NULL, Nodo *der=NULL)
:
dato(dat), izquierdo(izq), derecho(der) {}
// Miembros:
int dato;
Nodo *izquierdo;
Nodo *derecho;
};
// Punteros de la lista, para cabeza y nodo actual:
Nodo *raiz;
Nodo *actual;
int contador;
int altura;
public:
// Constructor y destructor bsicos:
ArbolABB() : raiz(NULL), actual(NULL) {}
~ArbolABB() { Podar(raiz); }
// Insertar en rbol ordenado:
void Insertar(const int dat);
// Borrar un elemento del rbol:
void Borrar(const int dat);
// Funcin de bsqueda:
bool Buscar(const int dat);
// Comprobar si el rbol est vaco:
bool Vacio(Nodo *r) { return r==NULL; }
// Comprobar si es un nodo hoja:
bool EsHoja(Nodo *r) { return !r->derecho && !r>izquierdo; }
// Contar nmero de nodos:
const int NumeroNodos();
const int AlturaArbol();
// Calcular altura de un int:
int Altura(const int dat);
// Devolver referencia al int del nodo actual:
int &ValorActual() { return actual->dato; }
// Moverse al nodo raiz:
void Raiz() { actual = raiz; }
// Aplicar una funcin a cada elemento del rbol:
Pgina 23 de 91
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Pgina 25 de 91
while(nodo->derecho) {
padre = nodo;
nodo = nodo->derecho;
}
}
// Intercambiar valores de no a borrar u nodo
encontrado
// y continuar, cerrando el bucle. El nodo
encontrado no tiene
// por qu ser un nodo hoja, cerrando el
bucle nos aseguramos
// de que slo se eliminan nodos hoja.
aux = actual->dato;
actual->dato = nodo->dato;
nodo->dato = aux;
actual = nodo;
}
}
else { // Todava no hemos encontrado el valor,
seguir buscndolo
padre = actual;
if(dat > actual->dato) actual = actual->derecho;
else if(dat < actual->dato) actual = actual>izquierdo;
}
}
}
// Recorrido de rbol en inorden, aplicamos la funcin
func, que tiene
// el prototipo:
// void func(int&);
void ArbolABB::InOrden(void (*func)(int&) , Nodo *nodo,
bool r)
{
if(r) nodo = raiz;
if(nodo->izquierdo) InOrden(func, nodo->izquierdo,
false);
func(nodo->dato);
if(nodo->derecho) InOrden(func, nodo->derecho, false);
}
// Recorrido de rbol en preorden, aplicamos la funcin
func, que tiene
// el prototipo:
// void func(int&);
void ArbolABB::PreOrden(void (*func)(int&), Nodo *nodo,
bool r)
{
if(r) nodo = raiz;
func(nodo->dato);
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Pgina 27 de 91
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Pgina 29 de 91
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Implementacin en Java
package jerarquicos; import excepciones.*;
public class ArbolBinarioBusqueda
{
NodoBinario raiz;
long numTotalInserciones, numTotalComparaciones;
public ArbolBinarioBusqueda()
{
raiz = null;
numTotalInserciones = 0;
numTotalComparaciones = 0;
}
public boolean esVacio(){return raiz == null;}
public String toString()
{
if ( this.raiz != null ) return
raiz.imprimirInOrden();
else return "";
}
public String imprimirPorNiveles ()
{
if ( this.raiz != null ) return
raiz.imprimirPorNiveles();
else return "";
}
public int tamanyo() { return NodoBinario.tamanyo(raiz);
}
public int altura() { return NodoBinario.altura(raiz);}
public double eMC(){ return
((double)numTotalComparaciones)/numTotalInserciones;}
protected NodoBinario buscar(Object clave, NodoBinario n)
throws ElementoNoEncontrado
{
if ( n == null ) throw new
ElementoNoEncontrado("**al buscar: "+clave+" no esta");
int resC = ((Comparable)n.dato).compareTo(clave) ;
if ( resC < 0 ) return buscar( clave, n.der
) ;
else if ( resC > 0 ) return buscar( clave,
n.izq ) ;
else return n;
}
protected NodoBinario insertar(Object clave, NodoBinario
n) throws ElementoDuplicado
{
if ( n == null )
{
numTotalInserciones++; return new
NodoBinario(clave);
}
Pgina 31 de 91
else {
int resC =
((Comparable)n.dato).compareTo(clave) ;
numTotalComparaciones++;
if ( resC < 0 ) n.der = insertar(clave,
n.der );
else if ( resC > 0 ) n.izq = insertar(clave,
n.izq ) ;
else throw new ElementoDuplicado("**al insertar:
"+clave+" ya esta");
return n ;
}
}
protected NodoBinario insertarTodos(Object clave,
NodoBinario n)
{
if ( n == null ) return new NodoBinario(clave);
else{
int resC =
((Comparable)n.dato).compareTo(clave) ;
if ( resC < 0 ) n.der = insertarTodos(clave,
n.der );
else n.izq = insertarTodos(clave, n.izq ) ;
return n ;
}
}
protected NodoBinario eliminar(Object clave, NodoBinario
n) throws ElementoNoEncontrado {
if ( n == null ) throw new
ElementoNoEncontrado("**al eliminar: "+clave+" no
esta");
int resC = ((Comparable)n.dato).compareTo(clave) ;
if ( resC < 0 ) n.der = eliminar( clave,
n.der );
else if ( resC > 0 ) n.izq = eliminar(
clave, n.izq ) ;
else if ( n.izq != null && n.der != null )
{
n.dato = buscarMin(n.der).dato; n.der =
eliminarMin(n.der);
} else n = ( n.izq != null ) ? n.izq: n.der ;
return n ;
}
protected NodoBinario eliminarMin(NodoBinario n)
{
if ( n.izq != null ) n.izq = eliminarMin(n.izq);
else n = n.der;
return n;
}
protected NodoBinario buscarMin (NodoBinario n)
{
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Pgina 33 de 91
rboles AVL
Un rbol AVL (llamado as por las iniciales de sus inventores: Adelson-Velskii
y Landis) es un rbol binario de bsqueda en el que para cada nodo, las
alturas de sus subrboles izquierdo y derecho no difieren en ms de 1.
No se trata de rboles perfectamente equilibrados, pero s son lo
suficientemente equilibrados como para que su comportamiento sea lo
bastante bueno como para usarlos donde los ABB no garantizan tiempos de
bsqueda ptimos.
El algoritmo para mantener un rbol AVL equilibrado se basa en
reequilibrados locales, de modo que no es necesario explorar todo el rbol
despus de cada insercin o borrado.
Un nodo es la unidad bsica sobre la que se construye un rbol y puede tener
cero o ms nodos hijos conectados a l, hasta un determinado numero de
nodos.
Los nodos pueden ser:
Raz, es el nodo que no tiene padre o el que inicia el rbol.
Padre, si desde el nodo a existe un enlace hasta el nodo b (decimos
que b es hijo de a).
Hoja, es un nodo que no tiene hijos.
La nica diferencia de los nodos de un rbol AVL con los de un rbol binario
comn, es la variable altura donde en la estructura nodo, la altura de la
rama izquierda no difiere en ms de una unidad de la altura de la rama
derecha. Con respecto a los enlaces, cada nodo se puede descomponer en 3
partes, una que guarda la informacin o datos y otras dos que permiten los
enlaces con hijos o subrboles izquierdo y derecho.
Los nodos de un rbol pueden almacenar cualquier tipo de dato. En nuestro
caso usaremos datos de tipo entero.
Para que el tiempo de ejecucin de esas funciones no sea O (n),
redefiniremos la funcin aprovechando el campo altura que tiene cada nodo
del rbol.
Un rbol AVL es un rbol en el cual cada nodo cumple con que todos los
nodos de su subrbol izquierdo son menores que la raz y todos los nodos
del subrbol derecho son mayores que la raz adems debe cumplir con la
propiedad de equilibrio que esta dado por la diferencia entre las alturas
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
del rbol derecho y el izquierdo. Por definicin, para un rbol AVL, este valor
debe ser -1, 0 1.
FE = altura subrbol derecho - altura subrbol izquierdo.
Gracias a esta forma de equilibrio (o balanceo), la complejidad de una
bsqueda en uno de estos rboles se mantiene siempre en orden de
complejidad O (Log ( n ) ).
Para conseguir esta propiedad de equilibrio, la insercin y el borrado de los
nodos se han de realizar de una forma especial. Si al realizar una operacin
de insercin o borrado se rompe la condicin de equilibrio, hay que realizar
una serie de rotaciones de los nodos. Como es una estructura no lineal, las
operaciones sobre estas estructuras no debern recorrer mucho para hallar el
elemento deseado.
Un rbol se puede recorrer de las siguientes formas:
Preorden, postorden, inorden y un recorrido por
niveles.
La profundidad de un rbol es la longitud del camino
que va desde la raz hasta el nodo.
Pgina 35 de 91
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Pgina 37 de 91
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Recibe un dato de tipo nodo (k1 es el que referencia a los hijos de una rama
derecha), y retorna una variable tipo nodo, hace el recorrido por la rama
izquierda y hace los cambios necesarios. Modifica la altura del rbol con la
variable altura que es referencia de la clase nodo; primero con los izquierdos
y despus con los derechos y retorna el giro final despus de equilibrar toda
la rama.
Pgina 39 de 91
Este es uno de los posibles rboles que pueden presentar esta estructura,
pero hay otras dos posibilidades. El nodo R puede tener una FE de -1, 0 1.
En cada uno de esos casos los rboles izquierdo y derecho de R (B y C)
pueden tener alturas de n y n-1, n y n, o n-1 y n, respectivamente.
El modo de realizar la rotacin es independiente de la estructura del rbol R,
cualquiera de las tres produce resultados equivalentes. Haremos el anlisis
para el caso en que FE sea -1.
En este caso tendremos que realizar dos rotaciones.
Llamaremos P al nodo que muestra el desequilibrio, el que tiene una FE
de -2. Llamaremos Q al nodo raz del subrbol izquierdo de P, y R al nodo raz
del subrbol derecho de Q.
1. Haremos una rotacin simple de Q a la izquierda.
2. Despus, haremos una rotacin simple de P a la derecha.
Con ms detalle, procederemos del siguiente modo:
1. Pasamos el subrbol izquierdo del nodo R como subrbol derecho de
Q. Esto mantiene el rbol como ABB, ya que todos los valores a la
izquierda de R siguen estando a la derecha de Q.
2. Ahora, el nodo R pasa a tomar la posicin del nodo Q, es decir,
hacemos que la raz del subrbol izquierdo de P sea el nodo R en lugar
de Q.
3. El rbol Q pasa a ser el subrbol izquierdo del nodo R.
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Pgina 41 de 91
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Implementacin en C++
//Arbol AVL en C++
#include <iostream>
using namespace std;
class AVL;
// Clase Nodo de Arbol AVL:
class Nodo {
public:
// Constructor:
Nodo(const int dat, Nodo *pad=NULL, Nodo *izq=NULL,
Nodo *der=NULL) :
dato(dat), padre(pad), izquierdo(izq), derecho(der),
FE(0) {}
// Miembros:
int dato;
int FE;
Nodo *izquierdo;
Nodo *derecho;
Nodo *padre;
friend class AVL;
};
class AVL {
private:
enum {IZQUIERDO, DERECHO};
// Punteros de la lista, para cabeza y nodo actual:
Nodo *raiz;
Nodo *actual;
int contador;
int altura;
public:
// Constructor y destructor bsicos:
AVL() : raiz(NULL), actual(NULL) {}
~AVL() { Podar(raiz); }
// Insertar en rbol ordenado:
void Insertar(const int dat);
// Borrar un elemento del rbol:
void Borrar(const int dat);
// Funcin de bsqueda:
bool Buscar(const int dat);
// Comprobar si el rbol est vaco:
bool Vacio(Nodo *r) { return r==NULL; }
// Comprobar si es un nodo hoja:
bool EsHoja(Nodo *r) { return !r->derecho && !r>izquierdo; }
// Contar nmero de nodos:
Pgina 43 de 91
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Pgina 45 de 91
if(nodo->izquierdo->FE == 1) RDD(nodo); //
Rotacin doble
else RSD(nodo);
//
Rotacin simple
salir = true;
}
else if(nodo->FE == 2) { // Rotar a izquierdas y
salir:
if(nodo->derecho->FE == -1) RDI(nodo); //
Rotacin doble
else RSI(nodo);
//
Rotacin simple
salir = true;
}
if(nodo->padre)
if(nodo->padre->derecho == nodo) rama = DERECHO;
else rama = IZQUIERDO;
nodo = nodo->padre; // Calcular FE, siguiente nodo
del camino.
}
}
// Rotacin doble a derechas
void AVL::RDD(Nodo* nodo)
{
cout << "RDD" << endl;
Nodo *Padre = nodo->padre;
Nodo *P = nodo;
Nodo *Q = P->izquierdo;
Nodo *R = Q->derecho;
Nodo *B = R->izquierdo;
Nodo *C = R->derecho;
if(Padre)
if(Padre->derecho == nodo) Padre->derecho = R;
else Padre->izquierdo = R;
else raiz = R;
// Reconstruir rbol:
Q->derecho = B;
P->izquierdo = C;
R->izquierdo = Q;
R->derecho = P;
// Reasignar padres:
R->padre = Padre;
P->padre = Q->padre = R;
if(B) B->padre = Q;
if(C) C->padre = P;
// Ajustar valores de FE:
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
switch(R->FE) {
case -1: Q->FE = 0; P->FE = 1; break;
case 0: Q->FE = 0; P->FE = 0; break;
case 1: Q->FE = -1; P->FE = 0; break;
}
R->FE = 0;
}
// Rotacin doble a izquierdas
void AVL::RDI(Nodo* nodo)
{
cout << "RDI" << endl;
Nodo *Padre = nodo->padre;
Nodo *P = nodo;
Nodo *Q = P->derecho;
Nodo *R = Q->izquierdo;
Nodo *B = R->izquierdo;
Nodo *C = R->derecho;
if(Padre)
if(Padre->derecho == nodo) Padre->derecho = R;
else Padre->izquierdo = R;
else raiz = R;
// Reconstruir rbol:
P->derecho = B;
Q->izquierdo = C;
R->izquierdo = P;
R->derecho = Q;
// Reasignar padres:
R->padre = Padre;
P->padre = Q->padre = R;
if(B) B->padre = P;
if(C) C->padre = Q;
// Ajustar valores de FE:
switch(R->FE) {
case -1: P->FE = 0; Q->FE = 1; break;
case 0: P->FE = 0; Q->FE = 0; break;
case 1: P->FE = -1; Q->FE = 0; break;
}
R->FE = 0;
}
// Rotacin simple a derechas
void AVL::RSD(Nodo* nodo)
{
cout << "RSD" << endl;
Nodo *Padre = nodo->padre;
Nodo *P = nodo;
Pgina 47 de 91
Nodo *Q = P->izquierdo;
Nodo *B = Q->derecho;
if(Padre)
if(Padre->derecho == P) Padre->derecho = Q;
else Padre->izquierdo = Q;
else raiz = Q;
// Reconstruir rbol:
P->izquierdo = B;
Q->derecho = P;
// Reasignar padres:
P->padre = Q;
if(B) B->padre = P;
Q->padre = Padre;
// Ajustar valores de FE:
P->FE = 0;
Q->FE = 0;
}
// Rotacin simple a izquierdas
void AVL::RSI(Nodo* nodo)
{
cout << "RSI" << endl;
Nodo *Padre = nodo->padre;
Nodo *P = nodo;
Nodo *Q = P->derecho;
Nodo *B = Q->izquierdo;
if(Padre)
if(Padre->derecho == P) Padre->derecho = Q;
else Padre->izquierdo = Q;
else raiz = Q;
// Reconstruir rbol:
P->derecho = B;
Q->izquierdo = P;
// Reasignar padres:
P->padre = Q;
if(B) B->padre = P;
Q->padre = Padre;
// Ajustar valores de FE:
P->FE = 0;
Q->FE = 0;
}
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Pgina 49 de 91
padre = nodo;
nodo = nodo->izquierdo;
}
}
// O buscar nodo ms derecho de rama
izquierda
else {
nodo = actual->izquierdo;
while(nodo->derecho) {
padre = nodo;
nodo = nodo->derecho;
}
}
// Intercambiar valores de no a borrar u nodo
encontrado
// y continuar, cerrando el bucle. El nodo
encontrado no tiene
// por qu ser un nodo hoja, cerrando el
bucle nos aseguramos
// de que slo se eliminan nodos hoja.
aux = actual->dato;
actual->dato = nodo->dato;
nodo->dato = aux;
actual = nodo;
}
}
else { // Todava no hemos encontrado el valor,
seguir buscndolo
padre = actual;
if(dat > actual->dato) actual = actual->derecho;
else if(dat < actual->dato) actual = actual>izquierdo;
}
}
}
// Recorrido de rbol en inorden, aplicamos la funcin
func, que tiene
// el prototipo:
// void func(int&, int);
void AVL::InOrden(void (*func)(int&, int) , Nodo *nodo,
bool r)
{
if(r) nodo = raiz;
if(nodo->izquierdo) InOrden(func, nodo->izquierdo,
false);
func(nodo->dato, nodo->FE);
if(nodo->derecho) InOrden(func, nodo->derecho, false);
}
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Pgina 51 de 91
int altura = 0;
actual = raiz;
// Todava puede aparecer, ya que quedan nodos por
mirar
while(!Vacio(actual)) {
if(dat == actual->dato) return altura; // dato
encontrado
else {
altura++; // Incrementamos la altura, seguimos
buscando
if(dat > actual->dato) actual = actual->derecho;
else if(dat < actual->dato) actual = actual>izquierdo;
}
}
return -1; // No est en rbol
}
// Contar el nmero de nodos
const int AVL::NumeroNodos()
{
contador = 0;
auxContador(raiz); // FUncin auxiliar
return contador;
}
// Funcin auxiliar para contar nodos. Funcin recursiva
de recorrido en
//
preorden, el proceso es aumentar el contador
void AVL::auxContador(Nodo *nodo)
{
contador++; // Otro nodo
// Continuar recorrido
if(nodo->izquierdo) auxContador(nodo->izquierdo);
if(nodo->derecho)
auxContador(nodo->derecho);
}
// Calcular la altura del rbol, que es la altura del
nodo de mayor altura.
const int AVL::AlturaArbol()
{
altura = 0;
auxAltura(raiz, 0); // Funcin auxiliar
return altura;
}
// Funcin auxiliar para calcular altura. Funcin
recursiva de recorrido en
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Pgina 53 de 91
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
ArbolInt.InOrden(Mostrar);
ArbolInt.Borrar(17);
cout << endl;
cout << "Borrar 17: ";
ArbolInt.InOrden(Mostrar);
cout << endl;
// Veamos algunos parmetros
cout << "N nodos: " << ArbolInt.NumeroNodos() << endl;
cout << "Altura de 1 " << ArbolInt.Altura(1) << endl;
cout << "Altura de 10 " << ArbolInt.Altura(10) <<
endl;
cout << "Altura de arbol " << ArbolInt.AlturaArbol()
<< endl;
cin.get();
// Arbol de cadenas:
AVL<Cadena> ArbolCad;
// Insercin de valores:
ArbolCad.Insertar("Hola");
ArbolCad.Insertar(",");
ArbolCad.Insertar("somos");
ArbolCad.Insertar("buenos");
ArbolCad.Insertar("programadores");
// Mostrar en diferentes ordenes:
cout << "InOrden: ";
ArbolCad.InOrden(Mostrar);
cout << endl;
cout << "PreOrden: ";
ArbolCad.PreOrden(Mostrar);
cout << endl;
cout << "PostOrden: ";
ArbolCad.PostOrden(Mostrar);
cout << endl;
// Borrar "buenos":
ArbolCad.Borrar("buenos");
cout << "Borrar 'buenos': ";
ArbolCad.InOrden(Mostrar);
cout << endl; */
cin.get();
return 0;
}
Pgina 55 de 91
Implementacin en Java
/*
* Nombre: Arbol_AVL.java
* Descripcin: implementacin de la clase Arbol AVL
* Autor: Mark Allen Weiss ("Estructuras de datos en
Java")
*/
public class Nodo_AVL{
// Atributos
public Comparable info; // dato
public Nodo_AVL hijo_izq; // hijo izquierdo
public Nodo_AVL hijo_der; // hijo derecho
public int altura; // altura del nodo
// Constructores
Nodo_AVL( Comparable dato)
{ this( dato, null, null ); }
Nodo_AVL( Comparable dato, Nodo_AVL izq, Nodo_AVL der ){
info = dato;
hijo_izq = izq;
hijo_der = der;
altura = 0;
}
}
/*
* Nombre: Arbol_AVL.java
* Descripcin: implementacin de la clase Arbol AVL
* Autor: Mark Allen Weiss ("Estructuras de datos en
Java")
*
*/
public class Arbol_AVL{
private Nodo_AVL raiz;
// Constructor
public Arbol_AVL()
{ raiz = null; }
public Comparable buscar_Menor( )
{ return dato_Nodo( buscar_Menor( raiz ) ); }
public Comparable buscar_Mayor( )
{ return dato_Nodo( buscar_Mayor( raiz ) ); }
public Comparable buscar( Comparable x )
{ return dato_Nodo( buscar( x, raiz ) ); }
public void imprimir_arbol( )
{
if( arbol_esVacio( ) )
System.out.println( "ARBOL VACIO !!!" );
else
inorden( raiz );
}
protected void inorden(Nodo_AVL r) // recorrido del rbol
{
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
if (r != null){
inorden(r.hijo_izq);
System.out.print(r.info + " ");
inorden(r.hijo_der);
}
}
private Comparable dato_Nodo( Nodo_AVL t )
{ return t == null ? null : t.info; }
public void insertar( Comparable x )
{ raiz = insertar( x, raiz ); }
private Nodo_AVL insertar( Comparable x, Nodo_AVL t ){
if( t == null )
t = new Nodo_AVL( x, null, null );
else if( x.compareTo( t.info ) < 0 ){
// insertar por el subarbol izquierdo
t.hijo_izq = insertar( x, t.hijo_izq );
// verificar la altura del subarbol
if( altura( t.hijo_izq ) - altura( t.hijo_der ) == 2 )
if( x.compareTo( t.hijo_izq.info ) < 0 )
t = rotacion_derecha( t ); // rotacion simple
else
//rotacin compuesta
t = rotacion_compuesta_derecha( t );
}
else if( x.compareTo( t.info ) > 0 ){
// insertar por el subarbol derecho
t.hijo_der = insertar( x, t.hijo_der );
// verificar la altura del subarbol
if( altura( t.hijo_der ) - altura( t.hijo_izq ) == 2 )
if( x.compareTo( t.hijo_der.info ) > 0 )
t = rotacion_izquierda( t ); // rotacion simple
else
// rotacin compuesta
t = rotacion_compuesta_izquierda( t ); }
else
; // dato duplicado --> no se inserta
t.altura = max( altura( t.hijo_izq ), altura( t.hijo_der
) ) + 1;
return t;}
private Nodo_AVL buscar_Menor( Nodo_AVL t ){
if( t == null )
return t;
while( t.hijo_izq != null )
t = t.hijo_izq;
return t;
}
private Nodo_AVL buscar_Mayor( Nodo_AVL t ){
if( t == null )
return t;
while( t.hijo_der != null )
Pgina 57 de 91
t = t.hijo_der;
return t;
}
private Nodo_AVL buscar( Comparable x, Nodo_AVL t ){
while( t != null )
if( x.compareTo( t.info ) < 0 )
t = t.hijo_izq;
else if( x.compareTo( t.info ) > 0 )
t = t.hijo_der;
else
return t; // hallado
return null; // No hallado
}
// Retorna la altura del nodo t
private static int altura( Nodo_AVL t )
{ return t == null ? -1 : t.altura; }
private static int max( int lhs, int rhs ) // altura
mayor
{ return lhs > rhs ? lhs : rhs; }
// rotacin simple --> derecha, actualizacin de la
altura
private static Nodo_AVL rotacion_derecha( Nodo_AVL k2 ){
Nodo_AVL k1 = k2.hijo_izq;
k2.hijo_izq = k1.hijo_der;
k1.hijo_der = k2;
k2.altura = max(altura(k2.hijo_izq),altura(k2.hijo_der
))+1;
k1.altura = max( altura( k1.hijo_izq ), k2.altura ) + 1;
return k1;
}
// rotacion simple --> izquierda, actualizacion de la
altura
private static Nodo_AVL rotacion_izquierda( Nodo_AVL k1
){
Nodo_AVL k2 = k1.hijo_der;
k1.hijo_der = k2.hijo_izq;
k2.hijo_izq = k1;
k1.altura = max(altura(k1.hijo_izq), altura(k1.hijo_der
)) + 1;
k2.altura = max( altura( k2.hijo_der ), k1.altura ) + 1;
return k2;}
// rotacin compuesta a la derecha y actualizacin de la
altura
private static Nodo_AVL rotacion_compuesta_derecha(
Nodo_AVL k3 )
{
k3.hijo_izq = rotacion_izquierda( k3.hijo_izq );
return rotacion_derecha( k3 );
}
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Pgina 59 de 91
rboles N-arios
Se trata de una generalizacin de los rboles binarios. En este tipo de
estructura, se pueden manejar mltiples subrboles asociados a cada nodo y
no solamente dos como en el caso de los rboles Binarios (adems, un nodo
puede contener mltiples llaves -claves).
Formalmente, se define un rbol N-ario como una estructura jerrquica, en la
cual, cada nodo tiene un nmero cualesquiera de subrboles n-arios
asociados y hasta un mximo de n.
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
rboles B
Un rbol B (Balanced - balanceado, equilibrado), es un caso particular de los
rboles Multivas. Una de sus caractersticas fundamentales, es que se trata
de mantener el rbol balanceado y garantizar un numero mnimo de claves
en cada nodo, exceptuando el nodo raz.
Los rboles B fueron introducidos por R. Bayer y E. McCreight en 1972, con el
propsito de mejorar el tiempo de acceso a estructuras de datos
almacenadas en memoria externa.
Cuando se almacena la estructura del rbol en memoria secundaria
(dispositivo de acceso lento: disco duro), y el acceder a un nodo, implica
acceder a un sector distinto del disco.
Entonces, se hace coincidir un sector fsico de la memoria, con el tamao de
un nodo, de manera que si un elemento ocupa e bytes, y un sector fsico
(disco) tiene un tamao f, en cada nodo se almacenarn f / e elementos.
De esta forma, se puede reducir notablemente el tiempo de acceso al disco
duro.
Los rboles B tienen las siguientes propiedades:
Los nodos terminales (hojas), tienen la misma altura.
Las claves de cada nodo deben estar ordenadas (ascendentemente).
No se permiten claves repetidas.
El orden, se determina con base al nmero de claves por nodo.
Si un nodo tiene N-claves, el nmero de subrboles que se pueden
desprender de l, es N+1, ninguno si es nodo terminal (hoja).
Un rbol es de orden N, cuando el numero mximo de subrboles
que se desprende de cualquier nodo es N+1, y el nmero mnimo de
subrboles no vacos es N + , exceptuando el nodo raz.
Cada nodo de un rbol B, esta conformado por variables de referencia
(apuntadores), las claves (llaves), y los datos (valores). Los componentes
dentro de cada nodo, estn ubicados de manera alterna. Usando las variables
de referencia, se enlaza con los nodos del siguiente nivel del rbol.
Pgina 61 de 91
Aplicaciones
Los rboles AVL (balanceados en altura), son muy buenos como estructuras
de datos en memoria primaria (RAM), pero muy deficientes para archivos, ya
que estos, requieren muchos accesos: por ser rboles binarios, son bastante
profundos.
Los rboles B surgieron (1972 - R.Bayer y E.McCreight) ante la necesidad de
mantener ndices en almacenamiento externo para acceder a las bases de
datos, es decir, con el grave problema de la lentitud de los discos duros, se
trat de aprovechar la capacidad de almacenamiento, para mantener una
gran cantidad de informacin, organizada de forma que el acceso a una clave
sea lo ms rpido posible.
En resumen, los rboles con mltiples hijos hacen que el mantenimiento de
ndices en memoria externa sea mucho ms eficiente y es justamente ste el
motivo por el que este tipo de rboles han sido los que tradicionalmente se
han usado para el mantenimiento de
ndices en sistemas de bases de datos.
rboles B
Una pgina es el elemento primario de la estructura y grficamente se podra
visualizar as:
48 50 60 70
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
rboles Rojinegro
Un rbol rojinegro es un rbol de bsqueda binaria con un bit extra de
almacenamiento por nodo: su color, el cual puede ser rojo o negro.
Los rboles rojinegros son estructuras basadas en rboles binarios
balanceados.
Un rbol rojinegro es un rbol de bsqueda binaria que satisface las
siguientes propiedades:
Cada nodo o es rojo o es negro
Cada hoja (nil) es negra
Si un nodo es rojo, entonces, sus hijos son negros
Cada camino de un nodo a cualquier descendiente tiene la misma
cantidad de nodos negros
Un rbol de bsqueda binaria es rojinegro si satisface las siguientes
propiedades:
1. Todo nodo es rojo o negro.
2. Toda hoja (nil) es negra.
3. La raz es negra.
4. Si un nodo es rojo, entonces sus hijos son negros.
5. Cada ruta simple de un nodo a una hoja descendiente contiene el
mismo nmero de nodos negros.
Estas propiedades hacen que un rbol rojinegro sea balanceado.
Pgina 63 de 91
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Rotaciones
Las operaciones Tree-Insert y Tree-Delete toman un tiempo O(log n)
en un rbol rojinegro con n llaves.
El resultado de insertar o eliminar nodos en un rbol rojinegro usando
el algoritmo de rboles de bsqueda binaria, podra violar las
propiedades de los rboles rojinegros.
De modo que cuando se realizan las operaciones de insercin o
eliminacin, puede que se deba cambiar los colores de algunos de los
nodos y tambin cambiar el apuntador al nodo.
El apuntador al nodo se cambia mediante una rotacin, la cual es una
operacin local que preserva el ordenamiento de las llaves.
La siguiente figura muestra los dos tipos de rotaciones: rotacin a la
izquierda y a la derecha.
Pgina 65 de 91
6
then root[T] y
7
else if x = left[p[x]]
8
then left[p[x]] y
9
else right[p[x]] y
10 left[y] x
---> Pone x a la izquierda de y
11 p[x] y
La siguiente figura muestra como opera Left-Rotate.
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Recorridos
Recorrido EntreOrden
RecorridoEntreOrden( x )
begin
if x <> nil then begin
RecorridoEntreOrden( left[x] );
writeln( x );
RecorridoEntreOrden( right[x] )
end
end;
Recorrido PreOrden
RecorridoPreOrden( x )
begin
if x <> nil then begin
writeln( x );
RecorridoPreOrden( left[x] );
RecorridoPreOrden( right[x] )
end
end;
Recorrido PosOrden
RecorridoPosOrden( x )
begin
if x <> nil then begin
RecorridoPosOrden( left[x] );
RecorridoPosOrden( right[x] )
writeln( x );
end
end;
Recorrido EntreOrden
Las rotaciones izquierda y derecha preservan entrerdenes. Esto es, si A es el
recorrido entreorden, x est antes que y en A y B es el recorrido entreorden
despus de aplicar una rotacin en x, entonces, x est antes que y en B.
En efecto, consideremos situacin derecha de la figura y una rotacin
izquierda sobre y.
Se tiene = x = = y = .
Despus de aplicar la rotacin a la izquierda el orden se preserva.
Pgina 67 de 91
Insercin
Al insertar nuevos elementos en rboles rojinegros, en tiempo O(log
n), se debe garantizar que el rbol resultante contine siendo
rojinegro
En los rboles rojinegros las hojas son vacas y negras
Los nuevos elementos se colocan como padres de hojas
Cada nuevo elemento se coloca como una estructura del rbol binario
Como las hojas deben ser negras, el nodo que contiene la llave a
insertarse se colorea como rojo
while x nil
do y x
then x left[x]
else x right[x]
8 p[z] y
9 if y = nil
10
then root[T] z
11
12
then left[y] z
13
else right[y] z
14
right[z] nil
15
left[z] nil
16
color[z] red
17
RB-INSERT-FIXUP(T,z)
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
RB-INSERT-FIXUP(T,z)
1
2
if color[y] = RED
---> Caso 1
color[y] BLACK
---> Caso 1
color[p[p[z]]] RED
---> Caso 1
z p[p[z]]
else if z = right[p[z]]
10
---> Caso 1
then z p[z]
---> Caso 2
11
Left-Rotate(T,z)
---> Caso 2
12
color[p[z]] BLACK
---> Caso 3
13
color[p[p[z]]] RED
---> Caso 3
14
Right-Rotate(T,p[p[z]])
---> Caso 3
15
16 color[root[T]] BLACK
Eliminacin
Como las otras operaciones en los rboles rojinegros, la eliminacin de un
nodo toma un tiempo O(log n).
Coincide con la operacin de eliminacin en los rboles de bsqueda
binaria
Sin embargo, es necesario mantener la estructura de los rboles
rojinegros
Para evitar repeticiones se introduce centinela, nil(A), el cual representa
las hojas del rbol rojinegro
Si el nodo suprimido y fuese rojo, entonces, las alturas negras no cambian
y, en tal caso, termina
Pgina 69 de 91
Si el nodo suprimido y fuese negro, entonces, las ramas que pasen por y
tienen un nodo negro menos, lo que viola la condicin de los rboles
rojinegros. En este caso es necesario ajustar colores.
El procedimiento RB-DELETE es una modificacin de TREE-DELETE, con tres
diferencias:
1. Todas las referencias a nil han sido reemplazadas por referencias al
centinela NIL [T].
2. Debido a la ausencia de condiciones de lmites, la asignacin p[x]
p[y] se realiza incondicionalmente.
3. Se hace un llamado al procedimiento RBDelete-Fixup
RB-DELETE(T,z)
1
if left[z] = nil[T] or right[z] = nil[T]
2
then y z
else y TREE-SUCCESSOR(z)
if left[y] nil[T]
then x left[y]
else x right[y]
p[x] p[y]
if p[y] = nil[T]
then root[T] x
10
else if y = left[p[y]]
11
then left[p[y]] x
12
else right[p[y]] x
13
if y z
14
15
16
17
18
if color[y] = BLACK
then RB-DELETE-FIXUP(T,x)
return y
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
RB-DELETE-FIXUP(T,x)
1
2
then w right[p[x]]
if color[w] = red
---> Caso 1
color[p[x]] RED
---> Caso 1
LEFT-ROTATE(T,p[x])
---> Caso 1
w right[p[x]] B Caso 1
10
11
x p[x]
---> Caso 2
---> Caso 2
12
13
---> Caso 3
14
color[w] RED
---> Caso 3
15
RIGHT-ROTATE(T,w)
---> Caso 3
16
w right[p[x]]
---> Caso 3
17
color[w] color[p[x]]
---> Caso 4
18
color[p[x]] BLACK
---> Caso 4
19
color[right[w]] BLACK
---> Caso 4
20
21
22
23
LEFT-ROTATE(T,p[x])
x root[T]
else (lo mismo que el then
cambiando right por left y viceversa)
color[x] BLACK
---> Caso 4
---> Caso 4
Pgina 71 de 91
Implementacin en Java
import
import
import
import
javax.swing.*;
java.awt.*;
java.util.*;
java.awt.event.*;
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
else
x = x.der;
}//fin while
z.padre = y;
if (y == null)
raiz = z;
else
if (z.elem.compareTo(y.elem) < 0)
y.izq = z;
else
y.der = z;
z.izq = null;
z.der = null;
z.color = red;
}
//**Mtodo que entrega un booleano. Se usa para saber
si un elemento est o no en el arbol
private boolean estaEnArbol(NodoRb a,Comparable elem)
{
if (a == null)
return false;
else
if (elem.compareTo(a.elem) == 0)
return true;
else
return estaEnArbol(a.izq,elem) ||
estaEnArbol(a.der,elem);
}
//*Luego de la eliminacin de un nodo eliminamos los
centinelas ya que solo se ocupa para ello
private void eliminarCentinelas(NodoRb x)
{
if (x == null)
return;
if( x.FLAG )
{
if( x.padre.izq.FLAG )
x.padre.izq = null;
if( x.padre.der.FLAG )
x.padre.der = null;
}
else
{
eliminarCentinelas(x.izq);
eliminarCentinelas(x.der);
Pgina 73 de 91
}
}
public void insertarRB(Comparable elem)
{
flag_esta = false;
if (estaEnArbol(raiz,elem)) // si elem ya se
encuenra en el arbol, no se vuelv6 a insertar
{
JOptionPane.showMessageDialog(null,""+(elem)+" ya se
encuentra en el arbol Red-Black.","Atencin.",
JOptionPane.PLAIN_MESSAGE);
flag_esta = true;
return;
}
eliminarCentinelas(raiz);
NodoRb x = new NodoRb(elem); //Se crea un nuevo
nodo para insertarlo en el arbol red-black
insertar_balanceado(x);
//Insertamos el
nuevo nodo al arbol primeramente como en un arbol ABB
while (x != raiz && x.padre.color == red)
//mientras el arbol no cumpla con las condiciones de RBtree
{
boolean nodo_Y_rojo = false;
//
variable booleana que almacena true si y es rojo y falso
si el nodo Y es negro
if (x.padre == x.padre.padre.izq) // si el
padre de x es igual al abuelo de x que apunta al hijo
izq.
{
NodoRb y = x.padre.padre.der;
if (y != null)
{
if (y.color == red)
{
//Recolorar para el caso 1 de insercin
x.padre.color = black;
y.color = black;
x.padre.padre.color = red;
x = x.padre.padre;
nodo_Y_rojo = true;
}
}
if ( !nodo_Y_rojo)
{
if (x == x.padre.der )
{
// caso 2: realizar una rotacion a la izq sobre x
x = x.padre;
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
rotarLeft(x);
}
// caso 3: Realizar rotacion
//a la derecha sobre el padre del padre de x
x.padre.color = black;
x.padre.padre.color = red;
rotarRight(x.padre.padre);
}
}
else
{
if (x.padre == x.padre.padre.der ) // si
el padre de x es igual al abuelo de x que apunta al hijo
der.
{
NodoRb y = x.padre.padre.izq; // aplicamos
los casos para esta situacion
if (y != null)
{
if (y.color == red)
{
//Recolorar para el caso 1 de insercin
x.padre.color = black;
y.color = black;
x.padre.padre.color = red;
x = x.padre.padre;
nodo_Y_rojo = true;
}
}
if (! nodo_Y_rojo)
{
// caso 2: Realizamos una rotacion a la derecha sobre el
nodo x
if (x == x.padre.izq)
{
x = x.padre;
rotarRight(x);
}
// caso 3: Realizamos una rotacion a la izquierda sobre
el abuelo de x
x.padre.color = black;
x.padre.padre.color = red;
rotarLeft(x.padre.padre);
}
}
Pgina 75 de 91
}
}
raiz.color = black;
arbol es negra
crearCentinela(raiz);
}
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Pgina 77 de 91
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
z.elem = y.elem;
mensaje += "\nComo el nodo Z es igual al nodo
Y, ahora la llave del nodo Z\n es igual a la llave del
nodo Y";
repaint(); // Es repintado el dibujo del
arbol
}
if( y.color == black )
{
mensaje += "\nEl color del nodo Y es black,
entonces. se llama al metodo para rebalancear el
arbol.\n"+
"Rebalancear arbol : Es el que se
encarga de devolver las propiedades red-black al arbol";
ventana_hija.texto.append(mensaje +"\n");
paso_a_paso();
repaint(); // Es repintado el dibujo del arbol
Corregir_red_black(x);//Corregir el posible
desbalanceo
}
else
{
ventana_hija.texto.append(mensaje +"\n");
paso_a_paso();
repaint(); // Es repintado el dibujo del
arbol
}
// se asigna null a las variables auxiliares
nodox = null;nodoy = null;nodoz = null;nodow =
null;
return y;// retorno el nodo ha eliminar
}
//**Mtodo de rotacin a la izquierda
//http://cuaima.ica.luz.ve/algoritmos/guiarojonegros.
pdf
private void rotarLeft(NodoRb x)
{
NodoRb y = x.der;
x.der = y.izq;
if( y.izq != null )
y.izq.padre = x;
y.padre = x.padre;
if( x.padre == null )
raiz = y;
else
if( x == x.padre.izq )
x.padre.izq = y;
else
x.padre.der = y;
Pgina 79 de 91
y.izq = x;
x.padre = y;
}
//**Mtodo de rotacin a la izquierda
private void rotarRight(NodoRb x)
{
NodoRb y = x.izq;
x.izq = y.der;
if( y.der != null )
y.der.padre = x;
y.padre = x.padre;
if( x.padre == null )
raiz = y;
else
if( x == x.padre.der )
x.padre.der = y;
else
x.padre.izq = y;
y.der = x;
x.padre = y;
}
//**Mtodo para Pintar los Nodos
public void paintChildren(Graphics g)
{
g.setFont(new Font("small",5,10) );
dibujo(g,raiz, 130, 10, 7.5, 0);
}
//Creacion de los centinelas para su uso en la
eliminacin
private void crearCentinela(NodoRb x)
{
if( x.izq == null ){
NodoRb centinela = new NodoRb(x);
x.izq = centinela;
}
else
{
crearCentinela(x.izq);
}
if( x.der == null )
{
NodoRb centinela = new NodoRb(x);
x.der = centinela;
}
else
{
crearCentinela(x.der);
}
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
}
//**Mtodo para el corregimiento del arbol. Al insertar o
eliminar nodos pudo haberse violado una o ms condiciones
del red-ba
private void Corregir_red_black(NodoRb x)
{
nodoz = nodoy = null;
while( x != raiz && x.color == black )// mientras
el arbol no sea red black
{
nodox=x;
if (x == x.padre.izq ) // Si x esta a la izq.
de su padre, entonces aplicamos 4 casos para Hijo
izquierdo
{
NodoRb w = x.padre.der;
nodow = w;
repaint();
ventana_hija.texto.append(" * Como el
nodo x representa al hijo izq, entonces, el nodo W
representa al hijo derecho\n");
/** Caso 1 **/
if (w.color == red)
{
ventana_hija.texto.append("* CASO 1:
Nodo W es Rojo\n");
paso_a_paso();
repaint();
ventana_hija.texto.append("---> 1) El
color del nodo W cambia a Negro\n");
paso_a_paso();
w.color = black;
// caso 1
repaint();
ventana_hija.texto.append("---> 2) El
color del padre del nodo X cambia a Rojo\n");
paso_a_paso();
repaint();
x.padre.color = red; // caso 1
ventana_hija.texto.append("---> 3) Se
realiza una rotacion a la izquierda sobre el padre del
nodo X\n");
paso_a_paso();
rotarLeft(x.padre);
// caso 1
repaint();
ventana_hija.texto.append("---> 4) El
nodo W pasa a ser el hijo der.del padre del nodo X\n");
paso_a_paso();
Pgina 81 de 91
w = x.padre.der;
// caso 1
repaint();
ventana_hija.texto.append("* FIN DEL
CASO 1\n");
}
/** Caso 2 **/
if (w.izq.color == black && w.der.color
== black )
{
ventana_hija.texto.append("CASO 2: El
color de los hijos del nodo W son Negros\n");
paso_a_paso();
ventana_hija.texto.append("---> 2) El
color del nodo W cambia a Rojo.\n");
paso_a_paso();
w.color = red;
// caso 2
repaint();
ventana_hija.texto.append("---> 2) El
nodo X pasa a ser el padre\n");
paso_a_paso();
x = x.padre;
// caso 2
repaint();
}
else
{
/** Caso 3 **/
3: El
1) El
2) El
3) Se
W\n");
paso_a_paso();
rotarRight(w);
// caso 3
repaint();
ventana_hija.texto.append("--->
4) El nodo W es ahora el hermano derecho del nodo X\n");
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
paso_a_paso();
w = x.padre.der;
nodow = w;
repaint();
// caso 3
}
/** Caso 4 **/
ventana_hija.texto.append("CASO
4: El nodo W es Negro y su hijo derecho. es Rojo\n");
paso_a_paso();
ventana_hija.texto.append("--->
1) El color del nodo W es ahora el color del padre del
nodo X\n");
paso_a_paso();
w.color = x.padre.color; // caso
4
repaint();
ventana_hija.texto.append("--->
2) El color del padre del nodo X es ahora negro\n");
paso_a_paso();
x.padre.color = black;
// caso
4
repaint();
ventana_hija.texto.append("--->
3) El color del hijo derecho de W cambia a Negro.\n");
paso_a_paso();
w.der.color = black;
// caso
4
repaint();
rotarLeft(x.padre);
// caso
4
ventana_hija.texto.append("--->
4) Se realiza una rotacion a izquierda al padre del nodo
X.\n");
paso_a_paso();
repaint();
ventana_hija.texto.append("--->
5) La raiz del arbol es rotulado como X\n");
paso_a_paso();
x = raiz;
// caso
4
nodox = x;
repaint();
ventana_hija.texto.append("--->
4) Finalmente el arbol se encuentra balanceado\n");
}
}
else
Pgina 83 de 91
{
if( x == x.padre.der )
// Si x esta
a la der. de su padre, entonces aplicamos 4 casos para
Hijo derecho
{
NodoRb w = x.padre.izq;
nodow = w;
repaint();
ventana_hija.texto.append("* Como
el nodo X representa al hijo derecho, entonces, el nodo W
representa al hijo izquierdo\n");
/** Caso 1 **/
if ( w.color == red )
{
ventana_hija.texto.append("*
CASO 1: El en nodo a eliminar W es Rojo\n");
paso_a_paso();
repaint();
ventana_hija.texto.append("--> 1) El color del nodo W cambia a negro\n");
paso_a_paso();
w.color = black;
// caso
1
repaint();
ventana_hija.texto.append("--> 2) El color del padre del nodo X cambia a rojo\n");
paso_a_paso();
x.padre.color = red;// caso 1
repaint();
ventana_hija.texto.append("--> 3) Se realiza una rotacion a la derecha sobre el padre
del nodo X\n");
paso_a_paso();
rotarRight(x.padre); // caso
1
repaint();
ventana_hija.texto.append("--> 4) El nodo W pasa a ser el hijo izquierdo del padre
del nodo X\n");
w = x.padre.izq;
// caso
1
repaint();
}
/** Caso 2 **/
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Pgina 85 de 91
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
repaint();
ventana_hija.texto.append("--> 6) Arbol Con balanceado Corregido....\n");
}
}
}
}// fin while
ventana_hija.texto.append("FINALIZADO EL
PROCESO DE REBALANCEO....\n");
x.color = black;// el nodo x debe ser black
nodox=x;
repaint();
}
//**Necesitamos buscar el nodo a eliminar
private NodoRb buscarNodo(NodoRb x , Comparable elem)
{
while( x != null && elem.compareTo(x.elem) != 0
)
if (elem.compareTo(x.elem) < 0 )
x = x.izq;
else
x = x.der;
return x;
}
//**Eliminamos el arbol
public void Limpiar()
{
Limpiar(raiz);
raiz = null;
repaint();
}
//**Para cada nodo se eliminan sus referencias
private void Limpiar(NodoRb x)
{
if( x != null ){
Limpiar(x.izq);
Limpiar(x.der);
x = null;
}
}
private void dibujo(Graphics g,NodoRb cabeza, int a,
int b, double c, int d)
{
Pgina 87 de 91
if ( cabeza != null ) {
if( cabeza.color == 0 )
g.setColor(Color.black);
else
g.setColor(Color.red);
if (!cabeza.FLAG) {
g.fillOval( 240 + a , 35 + b , 28
un ovalo
g.setColor(Color.white); //color
de la informacion del nodo (el numero)
, 28 ); //dibuja nodo
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
g.setColor(Color.black);
dibujo(g,cabeza.izq,a - (int)Math.pow(2,c) (int)Math.pow(2,d-6), b + 75, c - 1 , 1 );//Recursivo
para el dibujo de cada rama
dibujo(g,cabeza.der,a + (int)Math.pow(2,c) +
(int)Math.pow(2,d-6), b + 75, c - 1 , 2 );
}
}// fin dibujo
//Esta clase Crea la ventana de los resultados, se
compone de un panelsscroll, un jtextarea, y 3 botones
//Los botones sirven para ejecutar paso a paso, limpiar
el texto y para ejecutar directamente
class Child_window extends JFrame{
public JTextArea texto;
public JPanel control;
Child_window(){
JFrame sub_ventana = new JFrame();
sub_ventana.setLocation(750,1);
texto = new JTextArea(37,16);
JButton wait = new JButton("Pasos", new
ImageIcon("./images/Play_button.gif"));
wait.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
step = true; run_pid = false;
}
});
JButton clear = new JButton("Limpiar", new
ImageIcon("./images/erase_icon.gif"));
JButton run = new JButton("Run", new
ImageIcon("./images/run.gif"));
run.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
run_pid = true; step = false;
}
});
clear.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
texto.setText("");
}
});
control = new JPanel();
control.add(wait);
control.add(clear);
control.add(run);
sub_ventana.getContentPane().add(control,BorderLayout.SOU
TH);
Pgina 89 de 91
rboles
Fundamentos de Anlisis y Diseo de Algoritmos
Bibliografa
Estructuras de Datos y Algoritmos, Alberto Jaime Sisa, Prentice Hall.
Estructuras de datos en C. Aarn M. Tanenbaum, Y. Langsam & M.
Augenstein, Prentice Hall.
Estructuras de Datos, Osvaldo Cair & Silvia Guardati, McGraw Hill.
Estructuras de Datos en Java. Mark Allen Weiss, Addison-Wesley.
Fundamentos de Programacin. Algoritmos y Estructuras de Datos. Luis
Joyanes Aguilar, McGraw Hill.
Data Structure & Algorithms. Aho, Hopcroff, Ullman. Addison Wesley.
Cmo Programar en Java. Deitel & Deitel, Prentice Hall.
Introduccin a los algoritmos, T.Cormen.
Matematicas discretas Y Combinatoria, Ralph Grimaldi
Discrete Mathematics, Rosen
Algoritmos computacionales, Baase y Van Gelder.
Referencias
Donald E. Knuth. The Art Of Computer Programming, Volume 1 /
Fundamental Algorithms. 2nd edition, Addison Wesley.
Aho, Hopcroff, Ullman. Data Structure & Algorithms. Addison Wesley. 1983
Alberto Jaime Sisa. Estructuras de Datos y Algoritmos. Prentice Hall.
Aarn M. Tanenbaum, Y. Langsam & M. Augenstein. Estructuras de datos en
C. Prentice Hall.
R. Graham, D. Knuth, O. Patashnik, Concrete Mathematics, 2nd edition,
Addison Wesley, 1994. -> El problema de Josephus
G.M. Adelson-Velskii, E.M. Landis. An Algorithm for the Organization of
Information Dokl. Akad. Nauk SSSE, Mathemat., 146:2, pp. 263-266. 1962.
Referencias en Internet
rboles
http://rinconprog.metropoliglobal.com/CursosProg/ProgGen/Estr_Datos/index
.php?cap=1
http://informatica.uv.es/iiguia/2000/AED/
http://www.indiana.edu/~call/ejercicios.html
http://www.lcc.uma.es/~galvez/ftps.html
http://cuaima.ica.luz.ve/algoritmos/guiarojonegros.pdf
http://ingecomp.mforos.com/users/darkspawn2004/
Estructuras de Datos
http://gpsis.utp.edu.co/www/paginas/Tutoriales/EstDatos/
Pgina 91 de 91