You are on page 1of 27

Estructura de Datos y rboles Equilibrados

(Octubre -2011)
Contenido
INTRODUCCIN ....................................................................................................................................... - 1 -
EQUILIBRIO .............................................................................................................................................. - 1 -
RBOL AVL ............................................................................................................................................... - 2 -
CUNDO REORGANIZAR UN RBOL AVL .......................................................................................................... - 2 -
BALANCE ................................................................................................................................................ - 2 -
ROTACIONES ............................................................................................................................................ - 3 -
Ejercicio grfico ................................................................................................................................ - 5 -
IMPLEMENTACIN DE UN RBOL AVL ..................................................................................................... - 8 -
CDIGO DE NODEAVL<ELEMENT> ............................................................................................................. - 8 -
CDIGO DE BALANCEDTREE<ELEMENT> .................................................................................................... - 10 -
CDIGO PARA PROBAR UN BALANCEDTREE<ELEMENT> ................................................................................. - 23 -
EJERCICIO ............................................................................................................................................... - 24 -
CLASE PALABRA ...................................................................................................................................... - 24 -
MTODO PARA CONTAR PALABRAS .............................................................................................................. - 26 -
CONCLUSIN ......................................................................................................................................... - 26 -

Estructura de Datos y rboles Equilibrados
- 1 -
Introduccin
En esta publicacin continuamos con el tema de los rboles y nos introducimos en lo que se
conoce como rboles equilibrados.
Equilibrio
La distancia de un nodo a la raz determina la eficiencia con la que se puede localizar el nodo.
Dado cualquier nodo de un rbol, a sus hijos se puede acceder siguiendo slo un camino de
bifurcacin o de ramas. Esta caracterstica se conoce como balance o equilibrio. Para determinar
si un rbol est equilibrado, se calcula su factor de equilibrio.
El factor de equilibrio de un rbol binario es la diferencia en altura entre los subrboles derecho e
izquierdo.
Un rbol est perfectamente equilibrado si su equilibrio o balance es cero y sus subrboles son
tambin perfectamente equilibrados. Dado que esta situacin no se presenta frecuentemente, se
utiliza una definicin alternativa que dice: un rbol binario est equilibrado si la altura de sus
subrboles difiere en no ms de uno y sus subrboles son tambin equilibrados.
Existe una definicin de rbol perfectamente balanceado, que dice: "un rbol perfectamente
balanceado es aquel en el que para cada nodo el nmero de nodos en sus subrboles derecho e
izquierdo difieren como mximo en uno". Esta es la mxima expresin del equilibrio, sin embargo
el costo (en procesamiento) para mantener este tipo de rboles es demasiado por ello la industria
acepta y opera con el concepto de rbol equilibrado, en el que para cada nodo las alturas de los
subrboles derecho e izquierdo difieren en no ms de uno en valor absoluto.
Los siguientes esquemas muestran las diferencias entre cada concepto (definicin):

Perfectamente Equilibrado

Perfectamente Balanceado

Equilibrado
Fueron Adelson-Velskii y Landis quienes propusieron una solucin que se conoce como rbol AVL
la que permite mantener un rbol equilibrado cada vez que se agrega o extrae un nodo. En esta
solucin cuando se realiza la bsqueda de un elemento, en el peor de los casos se requiere 44%
ms comparaciones que en un rbol perfectamente balanceado de igual altura, esto es as porque
los subrboles difieren como mximo en 1 en sus alturas pero la cantidad de nodos puede ser muy
variable; La industria prefiere esta implementacin o sus variantes dado que es menos costosa a la
hora de reorganizar el rbol de manera que mantenga la estructura adecuada.
Los resultados empricos (Knuth, 1998) muestran que para un nmero "n" grande de nodos el
nmero promedio de accesos en una bsqueda es del orden de ln(n) + 0.25; de manera que
definitivamente vale la pena estudiar los rboles AVL.
Estructura de Datos y rboles Equilibrados
- 2 -
rbol AVL
Un rbol AVL es aquel en el que para cada nodo las alturas de los subrboles derecho e izquierdo
difieren en no ms de uno en valor absoluto.
Indudablemente se trata de un tipo de dato abstracto cuya implementacin se logra mediante un
rbol binario de bsqueda, en el que se modifica el comportamiento para agregar y extraer
elementos asegurando que la diferencia de altura entre los subrboles derecho e izquierdo de
cada nodo no sea mayor a uno en valor absoluto.
Para asegurar que la diferencia de altura entre los subrboles de cada nodo no sea mayor a uno en
valor absoluto es necesario "reorganizar" la forma del rbol binario de bsqueda despus de
agregar o extraer un nodo que provoque un cambio en las alturas de alguno de los subrboles.
Cundo reorganizar un rbol AVL
No siempre hace falta reorganizar la forma del rbol, a continuacin se muestra una mnima
deduccin que indica los casos en que es obligatorio reorganizar la forma del rbol:
Se defina hD como altura del subrbol derecho y hI como altura del subrbol izquierdo.
Si hD < hI y agrego en el subrbol derecho cambiando su altura entonces hD = hI.
Si hD = hI y agrego en el subrbol derecho cambiando su altura entonces hD > hI.
Si hD > hI y agrego en el subrbol derecho cambiando su altura entonces hD >> hI.
Solamente cuando la altura derecha es mayor que la altura izquierda y se agrega un nodo en el
subrbol derecho que cambia la altura del mismo se debe reorganizar el rbol.
A continuacin se analiza la situacin semejante para cuando se agrega en el subrbol izquierdo.
Si hI < hD y agrego en el subrbol izquierdo cambiando su altura entonces hI = hD.
Si hI = hD y agrego en el subrbol izquierdo cambiando su altura entonces hI > hD.
Si hI > hD y agrego en el subrbol izquierdo cambiando su altura entonces hI >> hD.
Solamente cuando la altura izquierda es mayor que la altura derecha y se agrega un nodo en el
subrbol izquierdo que cambia la altura del mismo se debe reorganizar el rbol.
Balance
Si en cada nodo se define el concepto de "Balance" como la diferencia entre la altura del subrbol
derecho menos la altura del subrbol izquierdo:
Balance = hD - hI
Los valores posibles de balance pueden ser:
Balance = 1 implica que altura subrbol derecho mayor que altura subrbol izquierdo.
Balance = 0 implica que las alturas de los dos subrboles son iguales.
Balance = -1 implica que la altura subrbol izquierdo es mayor que altura subrbol derecho.
Estructura de Datos y rboles Equilibrados
- 3 -
Almacenar el valor de "Balance" en la estructura interna de cada nodo permite establecer en qu
situacin despus de agregar o extraer un nodo se debe o no realizar la "reorganizacin" del rbol.
Rotaciones
El siguiente esquema muestra un caso sencillo en el que se consideran el nodo "P" y el nodo "Q"
que se encuentra a la derecha del nodo "P"; en el esquema el balance de "Q" es 0 y el balance de
"P" es 1, dado que los tres subrboles tiene una altura cuyo valor se representa como "h".
Se agrega un nodo en el subrbol derecho de "Q" cambiando la altura del mismo de manera que
despus de agregar el nodo los balances (si se calcularan) quedaran para el nodo "Q" en 1 y para
el nodo "P" en 2 lo que no puede ser debiendo realizarse una reorganizacin del rbol.
La solucin es lograr que el nodo "Q" sea padre del nodo "P" sin perder el subrbol izquierdo del
nodo "Q" que obviamente por el criterio de orden pasa a ser subrbol derecho de "P".



Antes
Despus


Solucin
Esta reorganizacin se conoce como Rotacin Simple Derecha - Derecha.
En el siguiente esquema se muestra otra posibilidad, en este caso se agrega un nodo que cambia
la altura en el subrbol izquierdo de "Q", que recordemos se encuentra en el subrbol derecho de
"P", particularmente se analiza el caso en que el nuevo nodo se agrega en el subrbol derecho del
nodo "R" que segn el esquema se encuentra a la izquierda del nodo "Q". El mismo anlisis se
puede hacer para el subrbol izquierdo de "R"



Antes

Despus

Alternativa
Estructura de Datos y rboles Equilibrados
- 4 -
Se observa que los balances (si se calcularan) en este caso resultaran balance de "Q" -1 y balance
de "P" 2, lo que no puede ser debiendo realizarse una reorganizacin del rbol.
La solucin es lograr que el nodo "R" sea padre de los nodos "P" y "Q" sin perder los subrboles
izquierdo y derecho del nodo "R" que por el criterio de orden el subrbol izquierdo de "R" pasa a
ser subrbol derecho de "P" y el subrbol derecho de "R" pasa a ser subrbol izquierdo de "Q".


Solucin 1er paso

Solucin 2do paso
Esta reorganizacin se conoce como Rotacin Doble Derecha - Izquierda.
Es importante destacar que despus de agregar el nodo en cualquiera de los casos no se calculan
los balances, se utiliza una tcnica recursiva para agregar el nodo y al retroceder en la recursin
una variable lgica pasada por referencia indica si la altura ha cambiado en cuyo caso cuando la
agregacin del nodo se produjo por una secuencia de balances 1 y 0 (como en los esquemas) es
cuando se debe realizar la rotacin, si la agregacin se hizo por la derecha es una rotacin simple y
si se hizo por la izquierda es una rotacin doble.
Se remarca la situacin en que la secuencia de balances 1 y 0 es la que indica cuando puede hacer
falta reorganizar el rbol, dado que al agregar por la derecha en esa secuencia de balances es la
que corresponde a la deduccin realizada. El valor de balance 1 indica que la altura del subrbol
derecho es mayor que la altura del subrbol izquierdo y el valor de balance 0 del nodo raz del
subrbol derecho indica que las alturas de sus subrboles estn equilibradas, agregar un nodo en
alguno de esos subrboles puede requerir de una rotacin lo que se descubre cuando cambia la
altura esta situacin se conoce por la variable lgica que se pasa por referencia en el proceso
recursivo.
El mismo anlisis se puede realizar para el caso en que se agregue un nodo por el subrbol
izquierdo. En este caso la secuencia de balances que debe tenerse en cuenta es -1 y 0, dado que el
valor de balance -1 indica que la altura del subrbol izquierdo es mayor que la altura del subrbol
derecho y el balance 0 del nodo raz del subrbol izquierdo indica que las alturas de sus subrboles
estn equilibradas; agregar un nodo por la izquierda de esta secuencia puede implicar una
rotacin, que nuevamente se descubre cuando cambia la altura lo que se indica con una variable
lgica utilizada en el proceso recursivo. Las rotaciones resultantes se conocen como Rotacin
Simple Izquierda - Izquierda y Rotacin Doble Izquierda - Derecha.
En ambos caso rotacin simple o doble, el nodo "P" es un nodo cualquiera, an cuando en el
esquema aparece como raz del rbol, puede existir un nodo "padre" de P y todo un rbol por
encima de este nodo. La cuestin es que la reorganizacin del rbol solamente se realiza desde el
Estructura de Datos y rboles Equilibrados
- 5 -
nodo que se agrega hasta el nodo "P" que se reemplaza por el nodo "Q" si la rotacin es simple o
el nodo "R" si la rotacin es doble, observen que en ambos casos la altura del subrbol a partir del
nodo "P" y la altura del subrbol resultante despus de aplicar la rotacin es la misma,
consecuentemente el balance de un supuesto nodo "padre" del nodo "P" no se ve afectada.
En el caso de una extraccin de un elemento del rbol, se aplican todas las consideraciones de los
rboles binarios de bsqueda; si el elemento a extraer est en un nodo hoja simplemente se
desconecta el nodo, en caso que el elemento se encuentre en un nodo con un descendiente se
conecta el nodo padre con el subrbol descendiente y en el caso que el elemento se encuentre en
un nodo con dos subrboles debe aplicarse alguna de las tcnicas mayor de los menores o menor
de los mayores adems de decidir realizar la extraccin por fusin o copia. Pero en el caso de
rboles equilibrado (particularmente los rboles AVL) adems de todo esto se debe considerar que
si se extrae un elemento (suprime un nodo) de un subrbol cuya altura es menor que la altura del
subrbol "hermano", si la altura cambia hacer falta reorganizar el rbol.
Deducciones semejantes a las realizadas para el caso de la agregacin de elementos son aplicables
en el caso de extraccin de elementos, se debe destacar que a diferencia de la agregacin que solo
requiere rotaciones hasta el nodo que se identifica como "P" (nodo cuyo balance es 1 o -1), en el
caso de las extracciones las rotaciones pueden avanzar desde el subrbol que contiene al
elemento a extraer hasta la raz misma del rbol de modo que puede consumir ms tiempo que la
agregacin.
En los rboles AVL la agregacin o eliminacin de un elemento puede requerir como mximo
1.44 lg(n+2) bsquedas, adems la agregacin puede requerir una rotacin simple o doble, y la
extraccin puede requerir 1.44 lg(n+2) rotaciones en el peor caso. Sin embargo los casos empricos
muestran que el caso promedio requiere lg(n) + .25 bsquedas, en el 78% de los casos las
extracciones no requieren rotaciones y el 53% de las agregaciones no requieren rotaciones.
Consecuentemente los rboles AVL son ampliamente utilizados en la industria incluso se
desarrollan implementaciones que extienden el criterio de balance, permitiendo diferencias de
altura de 2 o 3 en valor absoluto, duplicando la cantidad de bsquedas necesarias pero
disminuyendo la cantidad de reestructuraciones en un factor de 10
Ejercicio grfico
En este ejercicio, la secuencia de elementos 14, 6, 24, 35, 59, 17, 21, 32, 4, 7, 15, 22 se
agregar en rbol AVL inicialmente vaco.
Los cuatro primeros elementos se agregan de manera normal, buscando su posicin y
enlazando el nodo que contiene al elemento en cuestin.


{ 14 }



{ 14(6) }



{ 14(6,24) }


{ 14(6,24(,35) }
Estructura de Datos y rboles Equilibrados
- 6 -
Al agregar el elemento cuyo valor es 59, se observa que se hace por la derecha de una secuencia
de balances 1 y 0, se aplica la Rotacin Simple Derecha - Derecha.

NO es AVL


{ 14(6,35(24,59)) }

Al agregar el elemento cuyo valor es 17, se observa que se hace por la derecha de una secuencia
de balances 1 y 0, y en este caso se vez se aplica una la Rotacin Doble Derecha - Izquierda.

NO es AVL

{ 24(14(6,17),35(,59)) }
Los siguientes elementos se agregan de manera normal

{ 24(14(6,17(,21)),35(,59)) }

{ 24(14(6,17(,21)),35(32,59)) }
Estructura de Datos y rboles Equilibrados
- 7 -
En los siguientes esquemas se muestra una situacin particular, en la que despus de agregar el
nodo cuyo valor es 4, se debe agregar el nodo con valor 7 y luego el de valor 15. En los dos ltimos
casos (7 y 15) se observa que se realiza una agregacin sobre una secuencia -1 y 0 que
corresponde a los nodos 24 y 14 respectivamente, la agregacin se realiza por la izquierda de
dicha secuencia de modo que podra pensarse que hay que realizar alguna rotacin, sin embargo
debe observarse que en ambos casos la altura no cambia del subrbol en el que se agrega el nodo
no cambia, de manera que no se realiza rotacin alguna.


{ 24(14(6(4),
17(,21),35(32,59)) }

{ 24(14(6(4,7),
17(,21),35(32,59)) }

{ 24(14(6(4,7),
17(15,21),35(32,59)) }

El ltimo valor que se agrega es el 22, que se agrega en una secuencia -1 y 0, cambiando la altura
del subrbol de modo que debe aplicarse una rotacin y en este caso corresponde la Rotacin
Doble Izquierda - Derecha.


NO es AVL

{ 17(14(6(4,7),15),24(21(,22),35(32,59))) }
Es importante destacar que el nodo cuyo balance es 1 o -1 es el que se identifica con la referencia
"n", y corresponde al nodo "P" de la elaboracin terica, mientras que el nodo cuyo balance es 0
(sea el del subrbol izquierdo o derecho) se identifica con la referencia "n1" y es el que
corresponde al nodo "Q" en la elaboracin terica, el nuevo nodo se puede agregar
inmediatamente despus del nodo "Q" o ms abajo en el subrbol pero la rotacin (simple o doble
se realiza sobre los nodos "P", "Q" "R" si hace falta lo que se identifica con las referencias "n", "n1"
y "n2" en cada caso.
Estructura de Datos y rboles Equilibrados
- 8 -
Implementacin de un rbol AVL
Como en el caso de los rboles binarios de bsqueda, en este caso tambin hace falta un
componente que permita almacenar la informacin del elemento en el rbol y adems mantenga
las referencias a los subrboles izquierdo y derecho; adems este componente debe contar con un
campo y propiedad que mantenga el balance del nodo. Obviamente se trata de objeto del tipo
nodo que en este caso se muestra a continuacin.
Cdigo de NodeAVL<ELEMENT>

using System;

namespace DemoArbol6
{
/// <summary>
/// Clase para representar un nodo de un rbol binario
/// </summary>
/// <typeparam name="ELEMENT">Tipo de dato del elemento</typeparam>
public class NodeAVL<ELEMENT>
{

#region Estructura Interna
/// <summary>
/// Mantiene el elemento en el nodo
/// </summary>
private ELEMENT _Item;
/// <summary>
/// Mantiene el enlace al subrbol izquierdo
/// </summary>
private NodeAVL<ELEMENT> _Left;
/// <summary>
/// Mantiene el elace al subrbol derecho
/// </summary>
private NodeAVL<ELEMENT> _Right;
/// <summary>
/// Mantiene el factor de equilibrio del nodo
/// </summary>
private int _Balance;

#endregion

#region Propiedades Getters and Setters
/// <summary>
/// Facililta el acceso al elemento en el nodo
/// </summary>
public ELEMENT Item
{
get { return this._Item; }
set { this._Item = value; }
}
/// <summary>
/// Facilita el acceso al enlace al subrbol izquierdo
/// </summary>
public NodeAVL<ELEMENT> Left
{
Estructura de Datos y rboles Equilibrados
- 9 -
get { return this._Left; }
set { this._Left = value; }
}
/// <summary>
/// Facilita el acceso al enlace al subrbol derecho
/// </summary>
public NodeAVL<ELEMENT> Right
{
get { return this._Right; }
set { this._Right = value; }
}
/// <summary>
/// Facilita el acceso al factor de equilibrio del nodo
/// </summary>
public int Balance
{
get { return _Balance; }
set { _Balance = value; }
}
#endregion

#region Constructores
/// <summary>
/// Constructor por defecto, inicializa los campos de la estructura
/// interna en valores por defecto
/// </summary>
public NodeAVL()
{
this.Item = default(ELEMENT);
this.Left = null;
this.Right = null;
this.Balance = 0;
}
/// <summary>
/// Constructor especializado, permite fijar el elemento del nodo
/// </summary>
/// <param name="item">Elemento en el nodo</param>
public NodeAVL(ELEMENT item)
: this()
{
this.Item = item;
}
/// <summary>
/// Constructor especializado, permite fijar el elemento del nodo
/// y el valor de los enlaces a subrboles izquierdo y derecho
/// </summary>
/// <param name="item">Elemento en el nodo</param>
/// <param name="next">Enlace al subrbol izquierdo</param>
/// <param name="prev">Enlace al subrbol derecho</param>
public NodeAVL(ELEMENT item, NodeAVL<ELEMENT> left, NodeAVL<ELEMENT>
right)
: this()
{
this.Item = item;
this.Left = left;
this.Right = right;
}
Estructura de Datos y rboles Equilibrados
- 10 -
#endregion

/// <summary>
/// Metodo para probar las distintas formas en que
/// se puede recorrer un rbol
/// </summary>
public void Visit()
{
Console.Write("{0} ", this.Item.ToString());
}
}
}

Cdigo de BalancedTree<ELEMENT>
La siguiente es una implementacin bastante completa de un rbol binario de bsqueda
balanceado.
Se implementa el comportamiento para recorrer el rbol en orden, en pre orden y en post orden,
de este modo se puede verificar que la implementacin mantiene el orden previsto en la interface
IComparable. Para ello se codific un mtodo "Visit()" en el nodo; esto no es lo ms adecuado,
debera implementarse un mecanismo con "delegates" pero eso est fuera del alcance de la
materia, deben verlo en Programacin Orientada a Objetos.
Tambin se implement el comportamiento para determinar si un elemento est o no en el rbol
Contains( ... ), as como un mtodo que busca el nodo que contiene un elemento en particular
Find( ... ) que devuelve una referencia al nodo o null en caso que no exista.
Como siempre, se organiz el cdigo en regiones de manera que sea sencillo hallar la porcin de
cdigo que implementa cierto comportamiento.

using System;

namespace DemoArbol6
{
/// <summary>
/// Implementacin de rbol binario
/// </summary>
/// <typeparam name="ELEMENT">Tipo de dato de elementos que se
introduce en el rbol</typeparam>
public class BalancedTree<ELEMENT> where ELEMENT : IComparable
{

#region Estructura interna
/// <summary>
/// Mantiene la raz del rbol
/// </summary>
private NodeAVL<ELEMENT> _Root;
#endregion

#region Propiedades
/// <summary>
/// Facililta el acceso a la raz del rbol
/// </summary>
Estructura de Datos y rboles Equilibrados
- 11 -
protected virtual NodeAVL<ELEMENT> Root
{
get { return this._Root; }
set { this._Root = value; }
}
/// <summary>
/// Indica si el rbol est vacio
/// </summary>
public virtual Boolean IsEmpty
{
get { return this.Root == null; }
}
#endregion

#region Constructores
/// <summary>
/// Constructor por defecto
/// </summary>
public BalancedTree()
{
this.Root = null;
}
/// <summary>
/// Constructor especializado, permite asignar
/// el valor del item de la raz del rbol
/// </summary>
/// <param name="root">referencia al item de la raz del rbol, puede
ser null</param>
public BalancedTree(ELEMENT item)
: this()
{
this.Root = new NodeAVL<ELEMENT>(item);
}
/// <summary>
/// Constructor especializado, permite asignar
/// el valor del item de la raz del rbol y
/// los subrboles izquierdo y derecho
/// </summary>
/// <param name="root">referencia al item de la raz del rbol, puede
ser null</param>
/// <param name="left">referencia a un rbol que estar a la
izquierda, puede ser null</param>
/// <param name="right">referencia a un rbol que estar a la
derecha, puede ser null</param>
public BalancedTree(ELEMENT item, BalancedTree<ELEMENT> leftTree,
BalancedTree<ELEMENT> rightTree)
: this()
{
this.Root = new NodeAVL<ELEMENT>(item);
if (leftTree != null)
{
this.Root.Left = leftTree.Root;
}
if (rightTree != null)
{
this.Root.Right = rightTree.Root;
}
Estructura de Datos y rboles Equilibrados
- 12 -
}
#endregion

#region Comportamiento heredado de object
/// <summary>
/// Muestra la representacin del rbol en forma de lista
/// </summary>
/// <returns>Cadena con la representacin</returns>
public override string ToString()
{
return ToString(this.Root);
}
/// <summary>
/// Implementacin recursiva para mostrar un rbol en forma de lista
/// </summary>
/// <param name="root">Nodo del rbol</param>
/// <returns>Cadena con la representacin</returns>
protected virtual string ToString(NodeAVL<ELEMENT> root)
{
string s = string.Empty;
if (root != null)
{
s = root.Item.ToString();
if (root.Left != null)
{
s = s + " (" + ToString(root.Left);
if (root.Right != null)
{
s = s + ", " + ToString(root.Right);
}
s = s + ")";
}
else
{
if (root.Right != null)
{
s = s + " (, " + ToString(root.Right) + ")";
}
}
}
return s;
}
#endregion

#region Comportamiento para recorrer un rbol
/// <summary>
/// Implementacin del recorrido Pre Orden
/// para la instancia
/// </summary>
public virtual void PreOrder()
{
PreOrder(this.Root);
}
/// <summary>
/// Implementacin recursiva para recorrer un
/// rbol en Pre Orden
/// </summary>
Estructura de Datos y rboles Equilibrados
- 13 -
/// <param name="root">Nodo a visitar</param>
protected virtual void PreOrder(NodeAVL<ELEMENT> root)
{
if (root != null)
{
root.Visit();
PreOrder(root.Left);
PreOrder(root.Right);
}
}
/// <summary>
/// Implementacin del recorrido En Orden
/// para la instancia
/// </summary>
public virtual void InOrder()
{
InOrder(this.Root);
}
/// <summary>
/// Implementacin recursiva para recorrer un
/// rbol en En Orden
/// </summary>
/// <param name="root">Nodo a visitar</param>
protected virtual void InOrder(NodeAVL<ELEMENT> root)
{
if (root != null)
{
InOrder(root.Left);
root.Visit();
InOrder(root.Right);
}
}
/// <summary>
/// Implementacin del recorrido Post Orden
/// para la instancia
/// </summary>
public virtual void PostOrder()
{
PostOrder(this.Root);
}
/// <summary>
/// Implementacin recursiva para recorrer un
/// rbol en PostOrden
/// </summary>
/// <param name="root">Nodo a visitar</param>
protected virtual void PostOrder(NodeAVL<ELEMENT> root)
{
if (root != null)
{
PostOrder(root.Left);
PostOrder(root.Right);
root.Visit();
}
}
#endregion

#region Bsqueda de un elemento
Estructura de Datos y rboles Equilibrados
- 14 -
/// <summary>
/// Determina si un elemento est contenido en el rbol
/// </summary>
/// <param name="item">Elemento a controlar</param>
/// <returns>Verdadero si el elemento se encuentra contenido en el
rbol</returns>
public virtual Boolean Contains(ELEMENT item)
{
return Contains(this.Root, item);
}
/// <summary>
/// Implementacin recursivoa para determinar si un elemento
/// se encuentra contenido en el rbol
/// </summary>
/// <param name="root">Nodo raz del subrbol a considerar</param>
/// <param name="item">Elemento a controlar</param>
/// <returns>Verdadero si el elemento se encuentra contenido en el
rbol</returns>
protected virtual Boolean Contains(NodeAVL<ELEMENT> root, ELEMENT
item)
{
if (root == null)
{
return false;
}
if (item.CompareTo(root.Item) < 0)
{
return Contains(root.Left, item);
}
else
{
if (item.CompareTo(root.Item) > 0)
{
return Contains(root.Right, item);
}
}
return true;
}
/// <summary>
/// Busca un elemento en el rbol
/// </summary>
/// <param name="item">Elemento a buscar</param>
/// <returns>Referencia al elemento o null si no est en el
rbol</returns>
public virtual ELEMENT Find(ELEMENT item)
{
return Find(this.Root, item);
}
/// <summary>
/// Implementacin recursiva para buscar un elemento en el rbol
/// </summary>
/// <param name="root">Nodo raz del subrbol a considerar</param>
/// <param name="item">Elemento a buscar</param>
/// <returns>Referencia al elemento o null si no est en el
rbol</returns>
protected virtual ELEMENT Find(NodeAVL<ELEMENT> root, ELEMENT item)
{
Estructura de Datos y rboles Equilibrados
- 15 -
if (root == null)
{
return default(ELEMENT);
}
if (item.CompareTo(root.Item) < 0)
{
return Find(root.Left, item);
}
else
{
if (item.CompareTo(root.Item) > 0)
{
return Find(root.Right, item);
}
}
return root.Item;
}
#endregion

#region Agregar un elemento
/// <summary>
/// Agrega un elemento en el rbol equilibrado
/// </summary>
/// <param name="item">Elemento a agregar</param>
public virtual void Add(ELEMENT item)
{
bool flag = false;
this.Root = AddAVL(this.Root, item, ref flag);
}
/// <summary>
/// Implementacin recursiva para agregar un elemento en un
/// rbol equilibrado utilizando los conceptos de A V L
/// </summary>
/// <param name="root">Nodo raiz del subrbol a considerar</param>
/// <param name="item">Elemento a agregar</param>
/// <param name="flag">Bandera que indica que cambi la
altura</param>
/// <returns>Nodo raiz del subrbol considerado</returns>
protected virtual NodeAVL<ELEMENT> AddAVL(NodeAVL<ELEMENT> root,
ELEMENT item, ref bool flag)
{
NodeAVL<ELEMENT> n1;
// Si el rbol est vacio, simplement se agrega
// y se indica que cambi la altura
if (root == null)
{
root = new NodeAVL<ELEMENT>(item);
flag = true;
}
else
{
if (item.CompareTo(root.Item) < 0)
{
// El valor del elemento a agregar es menor
// que el valor de la raz del subrbol
// Se agrega recursivamente por la izquierda
root.Left = AddAVL(root.Left, item, ref flag);
Estructura de Datos y rboles Equilibrados
- 16 -
if (flag) // cambi la altura ?
{
switch (root.Balance)
{
case 1:
// antes derecha > izquierda, despus se equilibra
// y cambia la bandera
root.Balance = 0;
flag = false;
break;
case 0:
// anstes derecha = izquierda, despus izquierda mas
grande
// en algn nivel superior puede hacer falta un
rebalanceo
// la bandera queda como estaba (true)
root.Balance = -1;
break;
case -1:
// antes derecha < izquierda, hay que rebalancear
n1 = root.Left;
if (n1.Balance == -1)
{
// la izquierda de la izquierda es mayor
// rotacin simple izquierda-izquierda
root = LeftLeftRotation(root, n1);
}
else
{
// rotacin doble izquierda-derecha
root = LeftRightRotation(root, n1);
}
// subrbol ajustado cambia la bandera
flag = false;
break;
}
}
}
else
{
if (item.CompareTo(root.Item) > 0)
{
// El valor del elemento a agregar es mayor
// que el valor de la raz del subrbol
// Se agrega recursivamente por la derecha
root.Right = AddAVL(root.Right, item, ref flag);
if (flag) // cambi la altura ?
{
switch (root.Balance)
{
case 1:
// antes derecha > izquierda, hay que rebalancer
n1 = root.Right;
if (n1.Balance == 1)
{
// la derecha de la derecha es mayor
// rotacin simple derecha-derecha
Estructura de Datos y rboles Equilibrados
- 17 -
root = RightRightRotation(root, n1);
}
else
{
// rotacin doble derecha-izquierda
root = RightLeftRoation(root, n1);
}
// subrbol ajustado cambia la bandera
flag = false;
break;
case 0:
// antes derecha = izquierda, despus la derecha mas
grande
// en algn nivel superior puede hacer falta un
rebalanceo
// la bandera queda como estaba (true)
root.Balance = 1;
break;
case -1:
// antes derecha < izquierda, despues se equilibra
// y cambia la bandera
root.Balance = 0;
flag = false;
break;
}
}
}
else
{
// No se puede almacenar claves repetidas
throw new Exception("Claves repetidas");
}
}
}
return root;
}

#endregion

#region Extraer un elemento
/// <summary>
/// Extrae un elemento en el rbol equilibrado
/// </summary>
/// <param name="item">Elemento a extraer</param>
public virtual void Remove(ELEMENT item)
{
bool flag = false;
this.Root = RemoveAVL(this.Root, item, ref flag);
}
/// <summary>
/// Implementacin recursiva para extraer un elemento en un
/// rbol equilibrado utilizando los conceptos de A V L
/// </summary>
/// <param name="root">Nodo raiz del subrbol a considerar</param>
/// <param name="item">Elemento a extraer</param>
/// <param name="flag">Bandera que indica que cambi la
altura</param>
Estructura de Datos y rboles Equilibrados
- 18 -
/// <returns>Nodo raiz del subrbol considerado</returns>
protected virtual NodeAVL<ELEMENT> RemoveAVL(NodeAVL<ELEMENT> root,
ELEMENT item, ref bool flag)
{
// No se puede extraer nodos de un rbol vaco
if (root == null)
{
throw new Exception("No existe");
}
if (item.CompareTo(root.Item) < 0)
{
// El valor del elemento a extraer es menor
// que el valor de la raz del subrbol
// Se procesa recursivamente por la izquierda
root.Left = RemoveAVL(root.Left, item, ref flag);
if (flag)
{
// Cambi la altura, analizar el balance
root = LeftBalance(root, ref flag);
}
}
else
{
if (item.CompareTo(root.Item) > 0)
{
// El valor del elemento a extraer es mayor
// que el valor de la raz del subrbol
// Se procesa recursivamente por la derecha
root.Right = RemoveAVL(root.Right, item, ref flag);
if (flag)
{
// Cambi la altura, analizar el balance
root = RightBalance(root, ref flag);
}
}
else
{ // encontrado
NodeAVL<ELEMENT> q;
q = root;
if (q.Left == null)
{
// Un nico descendiente, cambia la altura
root = q.Right;
flag = true;
}
else
{
if (q.Right == null)
{
// Un nico descendiente, cambia la altura
root = q.Left;
flag = true;
}
else
{ // tiene dos subrboles !!!
root.Left = Repleace(root, root.Left, ref flag);
if (flag)
Estructura de Datos y rboles Equilibrados
- 19 -
{
// Cambi la altura, analizar el balance
root = LeftBalance(root, ref flag);
}
q = null;
}
}
}
}
return root;
}
#endregion

#region Utilitarios para extraer un elemento
/// <summary>
/// Aplica mayor de los menores controlando el cambio de altura
/// La tcnica aplicada es eliminacin por copia con bsqueda
recursiva
/// </summary>
/// <param name="n">Nodo que debe extraerse</param>
/// <param name="act">Nodo que corresponde al mayor de los
menores</param>
/// <param name="flag">Bandera que indica que cambi la
altura</param>
/// <returns></returns>
protected virtual NodeAVL<ELEMENT> Repleace(NodeAVL<ELEMENT> n,
NodeAVL<ELEMENT> act, ref bool flag)
{
if (act.Right != null)
{
// hay algo a la derecha, es mayor que el actual
act.Right = Repleace(n, act.Right, ref flag);
if (flag)
{
// Cambi la altura, analizar el balance
act = RightBalance(act, ref flag);
}
}
else
{
// act es el mayor de los menores
// copiar el elemento y anular la referencia
// cambia la altura
n.Item = act.Item;
n = act;
act = act.Left;
n = null;
flag = true;
}
return act;
}
/// <summary>
/// Analiza las posibles rotaciones cuando se extrajo un nodo de la
izquierda
/// </summary>
/// <param name="n">Nodo a considerar</param>
Estructura de Datos y rboles Equilibrados
- 20 -
/// <param name="flag">Bandera que indica que cambi la
altura</param>
/// <returns>Nodo considerado</returns>
protected virtual NodeAVL<ELEMENT> LeftBalance(NodeAVL<ELEMENT> n,
ref bool flag)
{
NodeAVL<ELEMENT> n1;
switch (n.Balance)
{
case -1:
// antes izquierda > derecha, despus se equilibra
n.Balance = 0;
break;
case 0:
// antes izquierda = derecha, despues se ajusta
// y cambia la altura
n.Balance = 1;
flag = false;
break;
case 1:
// antes izquierda < derecha, hay que rebalancer
// situaciones especiales para el cambio de altura
n1 = n.Right;
if (n1.Balance >= 0)
{
flag = false;
n = RightRightRotation(n, n1);
}
else
{
n = RightLeftRoation(n, n1);
}
break;
}
return n;
}
/// <summary>
/// Analiza las posibles rotaciones cuando se extrajo un nodo de la
derecha
/// </summary>
/// <param name="n">Nodo a considerar</param>
/// <param name="flag">Bandera que indica que cambi la
altura</param>
/// <returns>Nodo considerado</returns>
protected virtual NodeAVL<ELEMENT> RightBalance(NodeAVL<ELEMENT> n,
ref bool flag)
{
NodeAVL<ELEMENT> n1;
switch (n.Balance)
{
case -1:
// antes izquierda > derecha, hay que rebalancer
// situaciones especiales para el cambio de altura
n1 = n.Left;
if (n1.Balance <= 0)
{
if (n1.Balance == 0)
Estructura de Datos y rboles Equilibrados
- 21 -
{
flag = false;
}
n = LeftLeftRotation(n, n1);
}
else
{
n = LeftRightRotation(n, n1);
}
break;
case 0:
// antes izquierda = derecha, despus se ajusta
// y cambia la altura
n.Balance = -1;
flag = false;
break;
case 1:
// antes izquierda < derecha, despus se equilibra
n.Balance = 0;
break;
}
return n;
}
#endregion

#region Rotaciones
/// <summary>
/// Rotacion simple Izquierda - Izquierda
/// </summary>
/// <param name="n">Nodo raz a considerar</param>
/// <param name="n1">Nodo a la izquierda del raz a
considerar</param>
/// <returns>Nuevo nodo raz</returns>
protected virtual NodeAVL<ELEMENT> LeftLeftRotation(NodeAVL<ELEMENT>
n, NodeAVL<ELEMENT> n1)
{
n.Left = n1.Right;
n1.Right = n;
if (n1.Balance == -1)
{
n.Balance = 0;
n1.Balance = 0;
}
else
{
n.Balance = -1;
n1.Balance = 1;
}
return n1;
}
/// <summary>
/// Rotacion doble Izquierda - Derecha
/// </summary>
/// <param name="n">Nodo raz a considerar</param>
/// <param name="n1">Nodo a la izquierda del raz a
considerar</param>
/// <returns>Nuevo nodo raz</returns>
Estructura de Datos y rboles Equilibrados
- 22 -
protected virtual NodeAVL<ELEMENT> LeftRightRotation(NodeAVL<ELEMENT>
n, NodeAVL<ELEMENT> n1)
{
// Nodo a la derecha del nodo que est a la izquierda del nodo raz
a considerar
NodeAVL<ELEMENT> n2;
n2 = n1.Right;
n.Left = n2.Right;
n2.Right = n;
n1.Right = n2.Left;
n2.Left = n1;
n1.Balance = (n2.Balance == 1) ? -1 : 0;
n.Balance = (n2.Balance == -1) ? 1 : 0;
n2.Balance = 0;
return n2;
}
/// <summary>
/// Rotacion simple Derecha - Derecha
/// </summary>
/// <param name="n">Nodo raz a considerar</param>
/// <param name="n1">Nodo a la derecha del raz a considerar</param>
/// <returns>Nuevo nodo raz</returns>
protected virtual NodeAVL<ELEMENT>
RightRightRotation(NodeAVL<ELEMENT> n, NodeAVL<ELEMENT> n1)
{
n.Right = n1.Left;
n1.Left = n;
if (n1.Balance == 1)
{
n.Balance = 0;
n1.Balance = 0;
}
else
{
n.Balance = 1;
n1.Balance = -1;
}
return n1;
}
/// <summary>
/// Rotacion doble Derecha - Izquierda
/// </summary>
/// <param name="n">Nodo raz a considerar</param>
/// <param name="n1">Nodo a la derecha del raz a considerar</param>
/// <returns>Nuevo nodo raz</returns>
protected virtual NodeAVL<ELEMENT> RightLeftRoation(NodeAVL<ELEMENT>
n, NodeAVL<ELEMENT> n1)
{
// Nodo a la izquierda del nodo que est a la derecha del nodo raz
a considerar
NodeAVL<ELEMENT> n2;
n2 = n1.Left;
n.Right = n2.Left;
n2.Left = n;
n1.Left = n2.Right;
n2.Right = n1;
n.Balance = (n2.Balance == 1) ? -1 : 0;
Estructura de Datos y rboles Equilibrados
- 23 -
n1.Balance = (n2.Balance == -1) ? 1 : 0;
n2.Balance = 0;
return n2;
}
#endregion
}
}
Cdigo para probar un BalancedTree<ELEMENT>

using System;

namespace DemoArbol6
{
class Program
{
static void Main(string[] args)
{
// 14, 6, 24, 35, 59, 17, 21, 32, 4, 7, 15, 22
BalancedTree<int> a = new BalancedTree<int>();

Console.WriteLine("Agregaciones");
a.Add(14); a.InOrder(); Console.WriteLine(" -> {0}", a.ToString());
a.Add(6); a.InOrder(); Console.WriteLine(" -> {0}", a.ToString());
a.Add(24); a.InOrder(); Console.WriteLine(" -> {0}", a.ToString());
a.Add(35); a.InOrder(); Console.WriteLine(" -> {0}", a.ToString());
a.Add(59); a.InOrder(); Console.WriteLine(" -> {0}", a.ToString());
;
a.Add(17); a.InOrder(); Console.WriteLine(" -> {0}", a.ToString());
a.Add(21); a.InOrder(); Console.WriteLine(" -> {0}", a.ToString());
a.Add(32); a.InOrder(); Console.WriteLine(" -> {0}", a.ToString());
a.Add(4); a.InOrder(); Console.WriteLine(" -> {0}", a.ToString());
a.Add(7); a.InOrder(); Console.WriteLine(" -> {0}", a.ToString());
a.Add(15); a.InOrder(); Console.WriteLine(" -> {0}", a.ToString());
a.Add(22); a.InOrder(); Console.WriteLine(" -> {0}", a.ToString());

Console.WriteLine("Extracciones");
a.Remove(6); a.InOrder(); Console.WriteLine(" -> {0}",
a.ToString());
a.Remove(7); a.InOrder(); Console.WriteLine(" -> {0}",
a.ToString());
a.Remove(21); a.InOrder(); Console.WriteLine(" -> {0}",
a.ToString());
a.Remove(22); a.InOrder(); Console.WriteLine(" -> {0}",
a.ToString());
a.Remove(17); a.InOrder(); Console.WriteLine(" -> {0}",
a.ToString());
a.Remove(59); a.InOrder(); Console.WriteLine(" -> {0}",
a.ToString());

Console.WriteLine("Esta el 35 {0}", a.Contains(35));
Console.WriteLine("Esta el 99 {0}", a.Contains(99));
}
}
}
Estructura de Datos y rboles Equilibrados
- 24 -

La salida del programa es la siguiente:


Ejercicio
El siguiente ejemplo muestra cmo se puede utilizar un rbol binario de bsqueda balanceado
para contar cuantas veces aparece cada palabra en un texto dado, por supuesto que se puede
realizar el ejercicio de diferentes maneras pero la idea es utilizar un rbol AVL, de modo que
vamos a implementar un objeto que permita almacenar una palabra y un contador que se
incremente cada vez que esa palabra aparece en el texto.
Clase Palabra
Como se pretende utilizar los objetos del tipo Palabra en un rbol balanceado, esta clase debe
implementar la interface IComparable.

using System;

namespace DemoArbol6
{
public class Palabra : IComparable
{
/// <summary>
/// Mantiene la palabra misma
/// </summary>
private String cadena;
/// <summary>
/// Mantiene una cuenta de la cantidad de veces
/// que la palabra aparece en el texto
/// </summary>
private int cuenta;
/// <summary>
/// Constructor por defecto
/// </summary>
Estructura de Datos y rboles Equilibrados
- 25 -
public Palabra()
{
cadena = String.Empty;
cuenta = 0;
}
/// <summary>
/// Constructor especializado
/// </summary>
/// <param name="word">Valor de la palabra</param>
public Palabra(string word)
{
this.cadena = word;
this.cuenta = 1;
}
/// <summary>
/// Incrementa en uno el contador de ocurrencias
/// de la palabra
/// </summary>
/// <returns>Cantidad de ocurrencias de la palabra</returns>
public int Incrementa()
{
return (++this.cuenta);
}

#region IComparable Members
/// <summary>
/// Implementacin de la interface IComparable
/// </summary>
/// <param name="obj">Objeto con el que se compara el actual</param>
/// <returns>Entero menor a cero si el objeto actual es menor, mayor
a cero si el objeto actual es mayor y igual a cero si son
iguales</returns>
int IComparable.CompareTo(object obj)
{
if ((obj != null) && (obj is Palabra))
{
return this.cadena.CompareTo(((Palabra)obj).cadena);
}
throw new NotImplementedException();
}
#endregion

/// <summary>
/// Implementacin para entregar una representacin del objeto actual
/// </summary>
/// <returns>Cadena con la representacin del objeto actual</returns>
public override string ToString()
{
return String.Format("{0} {1}", this.cadena,
this.cuenta.ToString());
}
}
}
Obsrvese que la implementacin de CompareTo verifica que el objeto sea vlido y que sea del
tipo correcto, para recin proceder a realizar una comparacin entre cadenas.
Estructura de Datos y rboles Equilibrados
- 26 -
Mtodo para contar palabras
El siguiente cdigo se utiliza para contar las veces que cada palabra aparece en un texto, en el
ejemplo el texto se obtiene de un archivo (planto o txt) cuyo nombre (incluso la ruta de acceso) se
pasan como parmetro.
El mtodo lee archivo completo en memoria, luego genera un arreglo de palabras de acuerdo a
distintos separadores (mtodo Split de la clase String), luego declara e instancia un rbol
balanceado y para cada una de las palabras del texto verifica si existen en el rbol incrementa el
contador caso contrario agrega la palabra.
Finalmente muestra en orden los elementos del rbol y la estructura del mismo.

static void CuentaPalabras(String fileName)
{
if (!System.IO.File.Exists(fileName))
{
throw new Exception("No existe el archivo " + fileName);
}
String fileData = System.IO.File.ReadAllText(fileName,
System.Text.Encoding.Default);
String[] words = fileData.Split(" ,.\n\r".ToCharArray());
BalancedTree<Palabra> a = new BalancedTree<Palabra>();
Palabra temp, find;
foreach (String word in words)
{
if (!String.IsNullOrEmpty(word))
{
temp = new Palabra(word.ToUpper());
if ((find = a.Find(temp)) != null)
{
find.Incrementa();
}
else
{
a.Add(temp);
}
}
}
Console.WriteLine("Arbol en orden:");
a.InOrder();
Console.WriteLine("\n\nArbol (estructura):\n{0}", a.ToString());
}
Conclusin
Las implementaciones de rboles binarios de bsqueda y rboles balanceados no son simples pero
tampoco demasiado complejas, la lgica que realiza el comportamiento esperado ya est
desarrollada y probada. En el framework de los lenguajes de programacin orientados a objetos
no suele encontrarse clases que implementen rboles esto es as porque en general el tratamiento
de grandes cantidades de informacin se realiza con motores de base de datos en cuyo cdigo si
se encuentra este tipo de implementaciones.

You might also like