Вы находитесь на странице: 1из 29

Estructura de Datos y rboles

(Octubre-2011)
Contenido
INTRODUCCIN ....................................................................................................................................... - 1 -
RBOLES GENERALES Y TERMINOLOGA .................................................................................................. - 1 -
TERMINOLOGA ........................................................................................................................................ - 1 -
REPRESENTACIN...................................................................................................................................... - 2 -
Representacin como rbol invertido ................................................................................................ - 2 -
Representacin de lista .................................................................................................................... - 2 -
RBOLES BINARIOS .................................................................................................................................. - 2 -
RBOL BINARIO COMPLETO ......................................................................................................................... - 3 -
IMPLEMENTACIN DE UN RBOL BINARIO .............................................................................................. - 3 -
CLASE GENRICA NODE<ELEMENT> ............................................................................................................ - 4 -
CLASE GENRICA BINARYTREE<ELEMENT> .................................................................................................... - 6 -
Cdigo fuente de BinaryTree.cs......................................................................................................... - 6 -
Cdigo para probar un BinaryTree.cs ................................................................................................ - 9 -
Recorrido de un rbol binario ......................................................................................................... - 10 -
RBOL BINARIO DE BSQUEDA ............................................................................................................. - 13 -
AGREGAR ELEMENTOS EN UN RBOL BINARIO DE BSQUEDA .............................................................................. - 16 -
EXTRAER ELEMENTOS DE UN RBOL BINARIO DE BSQUEDA ............................................................................... - 17 -
IMPLEMENTACIN DE BINARYSEARCHTREE<ELEMENT> ................................................................................. - 22 -
Cdigo para probar la implementacin ........................................................................................... - 27 -
CONCLUSIONES ...................................................................................................................................... - 28 -

Estructura de Datos y rboles
- 1 -
Introduccin
Con esta publicacin comenzamos a ver una de las estructuras ms importantes en el
procesamiento de informacin, veremos los conceptos generales y algunas implementaciones.
El rbol es una estructura de datos muy importante en informtica y en ciencias de la
computacin, se trata de estructuras no lineales a diferencia de las que vimos anteriormente, las
listas, que se consideran lineales.
Los rboles se utilizan para representar frmulas algebraicas, organizar objetos en orden de tal
forma que las bsquedas sean muy eficientes y en aplicaciones diversas como inteligencia artificial
o algoritmos de cifrado. Casi todos los sistemas operativos almacenan sus archivos en rboles o
estructuras similares a rboles. Tambin se utilizan en el diseo de compiladores, procesamiento
de texto y algoritmos de bsqueda.
rboles generales y terminologa
De manera intuitiva, el concepto de rbol implica una estructura en la que los datos se organizan
de modo que los elementos de informacin estn relacionados entre s a travs de ramas.
Un rbol consta de un conjunto finito de elementos, llamados nodos y de un conjunto finito de
lneas dirigidas, llamadas ramas que conectan los nodos.
Un rbol es un conjunto de uno o ms nodos tales que: hay un nodo especial llamado raz y los
restantes se dividen en n 0 conjuntos disjuntos tal que cada uno de estos conjuntos es un rbol
y se los conoce como subrboles.
Terminologa
Adems del nodo raz, existen muchos trminos utilizados en la descripcin de los atributos de un
rbol, por ejemplo un nodo que tiene subrboles se conoce como padre de ellos, y los nodos
sucesores se llaman hijos. De este modo los hijos de un nodo y los hijos de estos se denominan
descendientes as como el padre y los abuelos se conocen como ascendientes. Los nodos del
mismo padre suelen llamarse hermanos y los nodos que no tienen descendientes se conocen
como hojas.
Se define nivel de un nodo a la distancia que ese nodo tiene al nodo raz, consecuente la raz tiene
nivel igual cero.
Un camino es una secuencia de nodos en los que cada nodo es adyacente al siguiente. Cada nodo
del rbol puede ser alcanzado siguiendo un nico camino que comienza en el nodo raz.
La altura o profundidad de un rbol es el nivel de la hoja del camino ms largo desde la raz ms
uno. Por definicin la altura de un rbol vaci es cero.
Un rbol se divide en subrboles, que es cualquier estructura conectada por debajo del nodo raz.
Cada nodo de un rbol es la raz de un subrbol que se define por el nodo y todos sus
descendientes.
Estructura de Datos y rboles
- 2 -
Representacin
Las formas ms frecuentes de representar un rbol en papel son como rbol invertido y como una
lista.
Representacin como rbol invertido
El nodo raz se encuentra en la parte ms alta de una jerarqua, de la que descienden ramas que
van a parar a los nodos hijos, y as sucesivamente.



Representacin de lista
Otro formato utilizado para representar un rbol es la lista entre parntesis. Esta notacin se
utiliza con expresiones algebraicas. En esta representacin, cada parntesis abierto indica el
comienzo de un nuevo nivel y cada parntesis cerrado completa un nivel y se mueve hacia arriba
un nivel en el rbol.
A (B (E), C (F), D (G, H))
rboles binarios
Un rbol binario es un rbol cuyos nodos no pueden
tener ms de dos subrboles. En un rbol binario,
cada nodo puede tener cero, uno o dos hijos. Se
conocen como el nodo de la izquierda y el nodo de la
derecha; obviamente esos nodos pueden ser la raz
de subrboles (binarios tambin) de manera
recursiva. En cualquier nivel "n", un rbol binario
puede contener de 1 a 2
n
nodos. El nmero de
nodos por nivel contribuye a la densidad del rbol.

Estructura de Datos y rboles
- 3 -
rbol binario completo
Un rbol binario completo de profundidad n es un rbol en el que para cada nivel desde el 0 al
n-1 tiene un conjunto lleno de nodos, y todos los nodos hoja a nivel n ocupan las posiciones ms
a la izquierda del rbol.
Un rbol binario completo que contiene 2n nodos a nivel n es un rbol lleno. Un rbol lleno es
un rbol binario que tiene el mximo nmero de entradas para su altura. Esto sucede cuando el
ltimo nivel est lleno.

rbol Binario Completo

rbol Binario Lleno
Los rboles binarios llenos presentan caractersticas interesantes como por ejemplo demostrar
que la altura h o profundidad de un rbol lleno de n nodos es: h = |log
2
n| + 1. Que
seguramente estudiaran en los cursos de Algebra.
Implementacin de un rbol binario
Es obvio que la
estructura de datos que
represente un tipo de
dato abstracto rbol
binario necesita de un
elemento del tipo Nodo
que mantenga la
informacin y los
enlaces necesarios; en
este caso un enlace al
subrbol izquierdo y
otro al subrbol
derecho.


Estructura de Datos y rboles
- 4 -
El diagrama muestra los componentes de la Clase Node que por supuesto debe ser realizada con
programacin genrica para poder almacenar cualquier tipo de objetos.
Clase genrica Node<ELEMENT>
Cdigo completo de la clase que se utilizar en la implementacin de rboles binarios.

using System;

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

#region Estructura Interna
/// <summary>
/// Mantiene el elemento en el nodo
/// </summary>
private ELEMENT _Item;
/// <summary>
/// Mantiene el enlace al subrbol izquierdo
/// </summary>
private Node<ELEMENT> _Left;
/// <summary>
/// Mantiene el elace al subrbol derecho
/// </summary>
private Node<ELEMENT> _Right;
#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 Node<ELEMENT> Left
{
get
{
return this._Left;
Estructura de Datos y rboles
- 5 -
}
set
{
this._Left = value;
}
}
/// <summary>
/// Facilita el acceso al enlace al subrbol derecho
/// </summary>
public Node<ELEMENT> Right
{
get
{
return this._Right;
}
set
{
this._Right = value;
}
}
#endregion

#region Constructores
/// <summary>
/// Constructor por defecto, inicializa los campos de la estructura
/// interna en valores por defecto
/// </summary>
public Node()
{
this.Item = default(ELEMENT);
this.Left = null;
this.Right = null;
}
/// <summary>
/// Constructor especializado, permite fijar el elemento del nodo
/// </summary>
/// <param name="item">Elemento en el nodo</param>
public Node(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 Node(ELEMENT item, Node<ELEMENT> left, Node<ELEMENT> right)
: this()
{
this.Item = item;
this.Left = left;
this.Right = right;
}
#endregion
Estructura de Datos y rboles
- 6 -

}
}
Clase genrica BinaryTree<ELEMENT>
La declaracin de clase para un rbol binario implementa el comportamiento visto hasta el
momento, que es constructores (adems del constructor por defecto) que nos permiten asignar el
valor del elemento de informacin que se almacena as como un constructor que nos permite
indicar los subrboles izquierdo y/o derecho.
Tambin se prev el mtodo que muestre un rbol binario, dado que es bastante complicado
realizar un grafico se implementa la representacin en formato de lista; para ello hace falta un
mtodo (en este caso protegido) que recursivamente procesa los nodos que integran el rbol
binario.
El siguiente diagrama de clase muestra todos estos elementos.

Cdigo fuente de BinaryTree.cs
A continuacin se detalla el cdigo fuente para la implementacin de la estructura de datos
BinaryTree (rbol binario):

using System;

namespace DemoArbol1
{
/// <summary>
/// Implementacin de rbol binario
/// </summary>
/// <typeparam name="ELEMENT">Tipo de dato de elementos que se
introduce en el rbol</typeparam>
public class BinaryTree <ELEMENT>
{

#region Estructura interna
/// <summary>
/// Mantiene la raz del rbol
Estructura de Datos y rboles
- 7 -
/// </summary>
private Node<ELEMENT> _Root;

#endregion

#region Propiedades

/// <summary>
/// Facililta el acceso a la raz del rbol
/// </summary>
protected Node<ELEMENT> Root
{
get
{
return this._Root;
}
set
{
this._Root = value;
}
}
/// <summary>
/// Indica si el rbol est vacio
/// </summary>
public Boolean IsEmpty
{
get
{
return this.Root == null;
}
}

#endregion

#region Constructores

/// <summary>
/// Constructor por defecto
/// </summary>
public BinaryTree()
{
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 BinaryTree(ELEMENT item)
: this()
{
this.Root = new Node<ELEMENT>(item);
}
/// <summary>
/// Constructor especializado, permite asignar
/// el valor del item de la raz del rbol y
Estructura de Datos y rboles
- 8 -
/// 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 BinaryTree(ELEMENT item, BinaryTree<ELEMENT> leftTree,
BinaryTree<ELEMENT> rightTree)
: this()
{
this.Root = new Node<ELEMENT>(item);
if (leftTree != null)
{
this.Root.Left = leftTree.Root;
}
if (rightTree != null)
{
this.Root.Right = rightTree.Root;
}
}

#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 string ToString(Node<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)
Estructura de Datos y rboles
- 9 -
{
s = s + " (, " + ToString(root.Right) + ")";
}
}
}
return s;
}

#endregion

}
}
Es interesante destacar que el constructor especializado controla que los parmetros de los
subrboles (izquierdo y/o derecho) sean distintos de nulo para poder recin acceder a sus
propiedades; esto permite asignar un subrbol con el valor nulo que justamente indica que no hay
subrbol.
Por otro lado vale la pena analizar el cdigo que se implementa en el mtodo que genera la
cadena con la representacin en formato de lista para un rbol binario. Por un lado vemos que el
mtodo pblico invoca a un mtodo protegido (esto se hace para implementar el proceso
utilizando programacin recursiva) y es en ese mtodo donde se va construyendo la cadena de
acuerdo al formato establecido para su representacin.
Cdigo para probar un BinaryTree.cs
El siguiente cdigo muestra cmo se puede construir un rbol binario y mostrar (la representacin
en forma de lista) del contenido.

using System;

namespace DemoArbol1
{
class Program
{
static void Main(string[] args)
{
// A(B(D,E),C(,F))

BinaryTree<char> a, a1, a2;
a1 = new BinaryTree<char>('B', new BinaryTree<char>('D'), new
BinaryTree<char>('E'));
a2 = new BinaryTree<char>('C', null, new BinaryTree<char>('F'));
a = new BinaryTree<char>('A', a1, a2);

Console.WriteLine(a.ToString());
}
}
}
La salida de este programa es la siguiente:

Estructura de Datos y rboles
- 10 -
Bueno, se puede hacer pero la verdad es que no parece ser muy til; esto es consecuencia que
para construir el rbol hay que saber donde se desea poner un nodo o un subrbol en particular lo
que definitivamente es muy engorroso.
Antes de tirar a la basura la implementacin realizada y analizar un caso ms interesante que
presenta mayor utilidad, veamos cmo se puede recorrer (mostrar, caminar por) un rbol binario.
Recorrido de un rbol binario
Dado que un rbol binario en cualquiera de sus nodos presenta tres elementos, la raz del rbol o
subrbol, el subrbol izquierdo y el subrbol derecho; es posible recorrer un rbol binario al
menos de tres formas posibles, todo depende de en qu momento se procesa o "visita" la raz del
nodo en cuestin.
De este modo diremos que se puede recorrer un rbol binario
Pre Orden - Se procesa la raz, el subrbol izquierdo, el subrbol derecho
En Orden - Se procesa el subrbol izquierdo, la raz, el subrbol derecho
Post Orden - Se procesa el subrbol izquierdo, el subrbol derecho, la raz.
Las implementacin ms sencillas para realizar este comportamiento son recursivas, pero se debe
tener en cuenta que pueden consumir muchsima memoria (en los sucesivos llamados) de modo
que tambin existen implementaciones iterativas que son ms complicadas de analizar y suelen
requerir de otras estructuras de datos (por ejemplo pilas) para su implementacin.
El cdigo que implementa los recorridos se muestra a continuacin, observen que se utilizan
mtodos protegidos (con un argumento del tipo Node<ELEMENT>) para implementar la
recursividad (esta porcin de cdigo debe agregarse a la declaracin de BinaryTree<ELEMENT>)

#region Comportamiento para recorrer un rbol

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

#endregion
Se debe destacar que se invoca al mtodo Visit(), del objeto del tipo Node<ELEMENT>; en este
ejemplo este mtodo solamente muestra en pantalla el contenido del objeto almacenado en el
nodo, en otra aplicacin este mtodo puede realizar algn tipo de procesamiento.
Este es el cdigo que se debe agregar en la declaracin de la clase Node<ELEMENT>

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

El cdigo para probar todo esto es el siguiente:

using System;

namespace DemoArbol3
{
class Program
{
static void Main(string[] args)
{
// A(B(C,D),E(,F))

BinaryTree<char> a, a1, a2;
a1 = new BinaryTree<char>('B', new BinaryTree<char>('C'), new
BinaryTree<char>('D'));
a2 = new BinaryTree<char>('E', null, new BinaryTree<char>('F'));
a = new BinaryTree<char>('A', a1, a2);

Console.WriteLine("Arbol {0}", a.ToString());
Console.WriteLine();

Console.Write("Pre orden ");
a.PreOrder();
Console.WriteLine();
Console.Write("En orden ");
a.InOrder();
Console.WriteLine();
Console.Write("Post orden ");
a.PostOrder();
Console.WriteLine();

Console.WriteLine();
}
}
}

La salida es la siguiente:


Estructura de Datos y rboles
- 13 -
La implementacin realizada hasta el momento es la ms sencilla y como se puede ver no presenta
ningn tipo de orden, por esa razn es el cdigo que crea el rbol el encargado de indicar dnde
quiere poner cada nodo o subrbol; por supuesto que existen aplicaciones que utilizan esta
implementacin, pero en realidad el rbol binario ordenado (aquel que presenta algn tipo de
ordenacin entre los valores de los nodos) es el que mayor uso tiene.
rbol Binario de Bsqueda
Un rbol binario que tiene los nodos ordenados de alguna manera se conoce como rbol Binario
de Bsqueda por que justamente al estar ordenado se puede buscar aplicando el criterio de
bsqueda binaria similar al utilizado con arreglos.
Un rbol binario de bsqueda es aquel en que, dado un nodo, todos los datos del subrbol
izquierdo son menores que los datos de ese nodo, mientras que todos los datos del subrbol
derecho son mayores (o iguales) que sus propios datos.


30 menor que 55
41 mayor que 30
75 mayor que 55
85 mayor que 75
4 menor que 30

donde se ubica otro 55 ?

Al existir un criterio de orden, es posible implementar el comportamiento: Agregar y Extraer
elementos de un rbol binario de bsqueda; dado que de acuerdo al valor del elemento, es
posible encontrar el lugar o ubicacin en el rbol donde debe estar el nodo que contiene a dicho
elemento.
Obviamente un rbol binario de bsqueda es un rbol binario lo que nos est indicando que no
hay que realizar otra implementacin, simplemente se puede heredar todo lo que un rbol binario
tiene y en esta sub clase implementar el nuevo comportamiento, que sern (en un principio) los
mtodos para agregar y extraer elementos del rbol.

Para agregar elementos en un rbol binario de bsqueda en primer lugar se debe hallar el lugar
donde el elemento debe ubicarse y luego crear un nodo que lo contenga.
La forma de buscar un lugar o valor en un rbol binario de bsqueda es justamente aplicando la
tcnica de bsqueda binaria; esto quiere decir que se compara el valor a buscar con el valor del
Estructura de Datos y rboles
- 14 -
nodo raz, si lo que se busca es menor entonces se debe procesar el subrbol izquierdo, si lo que
se busca es mayor o igual entonces se debe procesar el subrbol derecho.
Como en este caso estamos buscando un lugar y no un valor puntual (que no es lo mismo) el
proceso indicado en el prrafo anterior se realiza hasta que no hay subrbol lo que indica que se
encontr el lugar que le corresponde al valor que se desea agregar.

El siguiente diagrama de clases muestra la jerarqua de clases que utilizaremos:


En esta oportunidad nos enfrentamos a un punto importante del paradigma orientado a objetos,
ya se coment algo de esto en la una publicacin sobre la implementacin de listas (en el caso de
una lista ordenada) pero voy a volver sobre el tema.
El rbol binario de bsqueda es en trminos de estructura de datos un "contenedor" de
informacin, que "contiene" dicha informacin de una forma en particular, pero no sabe que es lo
que est "conteniendo" de manera que tampoco puede saber cuando un elemento es mayor,
Estructura de Datos y rboles
- 15 -
menor o igual que otro elemento. De manera que esta responsabilidad, la de saber cundo un
elemento es mayor, menor o igual que otro elemento es justamente un comportamiento propio
de cada elemento y no del rbol binario de bsqueda.
Lo que se est planteando es que los objetos del tipo ELEMENT deben saber cuando son mayores,
menores o iguales a otros elementos caso contrario no se pueden meter dentro de un rbol
binario de bsqueda dado que el rbol no sabe compararlos. Este tipo de programacin es
bastante comn y debe implementarse haciendo uso de una interface (contrato de
comportamiento) que obligue a los objetos del tipo ELEMENT a realizar la comparacin.
Por lo expuesto, la declaracin de la clase debe ser as:

/// <summary>
/// Implementacin de rbol binario de bsqueda
/// </summary>
/// <typeparam name="ELEMENT">Tipo de dato de elementos que se
introduce en el rbol</typeparam>
public class BinarySearchTree<ELEMENT> : BinaryTree<ELEMENT> where
ELEMENT : IComparable

Lo que se est diciendo es que la clase BinarySearchTree es una subclase de BinaryTree, ambas
son clases genricas porque utilizan un patrn que se denomina ELEMENT al que se le exige que
implemente la interface IComparable (que es la que contiene el mtodo CompareTo
estandarizado).
Cuando se trate de compilar una porcin de cdigo para crear un objeto del tipo BinarySearchTree
para objetos que no implementen la interface, el compilador generar un error recordndole al
desarrollador que debe implementar la interface.
Este mtodo CompareTo est estandarizado porque todos en el mundo saben que devuelve un
valor entero que si es menor a cero indica que el objeto que ejecuta el mtodo es menor que el
objeto que se pasa como parmetro, cuando el valor devuelto es mayor a cero indica que el objeto
que ejecuta el mtodo es mayor que el objeto pasado como parmetro y cuando es igual a cero
indica que ambos objetos son iguales.
Es importante destacar que la subclase debe implementar sus propios constructores, en este caso
lo que se hace es invocar a los constructores de la clase base:

#region Constructores (no se heredan)
/// <summary>
/// Constructor por defecto
/// </summary>
public BinarySearchTree()
: base()
{
}
/// <summary>
/// Constructor especializado que crea un rbol
/// binario de busqueda para el elemento indicado
/// </summary>
/// <param name="item">Elemento</param>
public BinarySearchTree(ELEMENT item)
Estructura de Datos y rboles
- 16 -
: base(item)
{
}
#endregion

Agregar elementos en un rbol binario de bsqueda
La implementacin para agregar elementos en un rbol binario de bsqueda que se muestra a
continuacin utiliza una tcnica iterativa, en los libros pueden hallar la misma operacin pero
utilizando una tcnica recursiva; la forma iterativa es ms econmica.

/// <summary>
/// Agrega un elemento al rbol binario de bsqueda
/// </summary>
/// <param name="item">Elemento a agregar</param>
public void Add(ELEMENT item)
{
if (this.IsEmpty)
{
this.Root = new Node<ELEMENT>(item);
}
else
{
// Implementacin iterativa que busca la posicin
// para el nuevo elemento de acuerdo al criterio
// de comparacin que se establece en el mtodo
// CompareTo de cada Item
Node<ELEMENT> temp = this.Root, prev = null;
while (temp != null)
{
prev = temp;
if (temp.Item.CompareTo(item) > 0)
{
temp = temp.Left;
}
else
{
temp = temp.Right;
}
}
// Implementacin que crea y agrea un nodo
// de acuerdo al criterio de comparacin que se
// establece en el mtodo CompareTo de cada Item
temp = new Node<ELEMENT>(item);
if (prev.Item.CompareTo(item) > 0)
{
prev.Left = temp;
}
else
{
prev.Right = temp;
}
}
}
Estructura de Datos y rboles
- 17 -

Observen que lo primero a controlar es si el rbol est vaco, en cuyo caso el nuevo elemento se
convierte en la raz del rbol; caso contrario se busca el lugar que le corresponde y finalmente se
lo agrega, siempre creando el nodo que lo contiene.
Extraer elementos de un rbol binario de bsqueda
Cuando se trata de extraer un elemento de un rbol binario de bsqueda lo primero que se debe
cuidar es que el elemento exista en el rbol, caso contrario el mtodo provocar una excepcin.
Pueden presentarse varias posibilidades, la ms simple es la que se muestra a continuacin, en la
que se desea extraer el elemento de valor 41, que se encuentra en un nodo hoja.

En este caso se procede a "desconectar" el nodo que contiene al elemento y devolver el elemento
mismo.
Otra posibilidad es cuando el nodo que contiene al elemento que se desea extraer tiene un nico
descendiente, puede ser por la izquierda o la derecha pero existe un descendiente. El siguiente
esquema muestra el caso en el que se desea extraer el elemento de valor 75, que se encuentra en
un nodo que tiene un descendiente.

En esta situacin se procede a "desconectar" el nodo que tiene el elemento a extraer pero hay que
tener la precaucin de no perder el subrbol que este nodo tiene, de modo que se procede a
conectar con el padre del nodo cuyo elemento se est extrayendo.
Estructura de Datos y rboles
- 18 -
El algoritmo solamente debe controlar si se trata del subrbol izquierdo o derecho y todo funciona
sin mayores problemas.
La ltima posibilidad, y la ms compleja, es cuando el elemento que se desea extraer est en un
nodo que tiene los dos subrboles; no se puede perder ninguno de ellos y adems se debe
mantener el criterio de orden que justamente caracteriza a los rboles binarios de bsqueda.
Situacin en la que se desea extraer el elemento de valor 55.

Se aplica una tcnica conocida como "el mayor de los menores", que consiste en hallar el nodo
cuyo valor es el ms grande (mayor) de todos los nodos cuyos valores son menores que el que se
desea extraer. En el ejemplo los menores al elemento 55 son los que estn a su izquierda y de
todos ellos, el mayor es el elemento 41. Una vez que se encuentra el nodo cuyo valor es el mayor
de los menores se procede a "ajustar" los enlaces del rbol y finalmente desconectar el nodo.
El siguiente diagrama muestra una variante ms complicada de esta ltima posibilidad:

Estructura de Datos y rboles
- 19 -
Observen que el "mayor de los menores" es el nodo cuyo valor es 48, pero en este caso tiene
descendencia obviamente por la izquierda caso contrario no sera el mayor de los menores.
As como existe la tcnica "mayor de los menores" existe otra que se conoce como "menor de los
mayores" que es lo mismo solo que con la otra rama o descendencias del nodo que se desea
extraer.
El "ajuste" de los enlaces se puede hacer de dos maneras una de ellas conocida como "eliminacin
por fusin" y la otra "eliminacin por copia".

En la "eliminacin por copia", una vez que se encuentra el nodo mayor de los menores lo que se
hace es intercambiar su contenido (he ah la copia) con el que se va a extraer; en el ejemplo el
valor 48 va a estar donde ahora est el 55 y se puede conectar el enlace derecho del nodo cuyo
valor es 41 con la descendencia izquierda del mayor de los menores, de este modo el rbol sigue
siendo un rbol binario de bsqueda porque respeta el criterio de orden establecido. Esta
modalidad generalmente es utilizada en lenguajes NO orientados a objetos dado que en ellos se
debe manipular punteros y suele ser ms sencilla de utilizar.
A continuacin se muestra el esquema de cmo opera la "eliminacin por copia"

(1) elemento encontrado

(2) mayor de los menores
En el esquema (1) se muestra la situacin cuando se ha encontrado el elemento a extraer, la
tcnica utiliza varias referencias para realizar su tarea (ya las vern en el cdigo que se encuentra
ms adelante); el elemento a extraer se encuentra en el nodo referenciado por "find", la
Estructura de Datos y rboles
- 20 -
referencia "prev" se utiliza para indicar el nodo anterior (padre) del que se pretende extraer,
"node" es una copia de esta referencia y "temp" se utiliza para localizar los nodos cuyos valores
son menores al que se pretende retirar.
En el esquema (2) se muestra cmo se aplica la tcnica del mayor de los menores, de manera que
la referencia "temp" indica el nodo que contiene al mayor elemento de todos los menores al que
se pretende retirar; la referencia "last" se utiliza para indicar el anterior al mayor de los menores
necesaria para ajustar el rbol.
Los pasos siguientes son:

(3) realiza la copia

(4) ajusta los enlaces
El esquema (3) muestra cmo se realiza la copia del contenido del nodo "mayor de los menores" al
nodo que se extrae, si el mtodo devuelve el valor hay que tener la precaucin de salvarlo antes.
En el esquema (4) se ajustan los enlaces de manera que no se pierda el subrbol que puede estar a
la izquierda del mayor de los menores.
Finalmente el algoritmo completo realiza una verificacin si se trata del nodo raz, de manera que
se actualice su valor en la estructura interna del rbol binario de bsqueda.

En la "eliminacin por fusin", una vez que se encuentra el nodo mayor de los menores lo que se
hace es fusionar (reorganizar) los subrboles de manera que se conserve el criterio de orden. Esta
modalidad es ms utilizada en los lenguajes orientados a objetos en los cuales se manipulan
Estructura de Datos y rboles
- 21 -
referencias (que no son otra cosa ms que punteros) y permite realizar con sencillez la fusin de
subrboles.
Los siguientes esquemas muestran los pasos que se llevan a cabo al aplicar esta tcnica.

(1) elemento encontrado

(2) mayor de los menores
En el esquema (1) se muestra la situacin cuando se ha encontrado el elemento a extraer, esta
tcnica utiliza una referencia menos para realizar su tarea; el elemento a extraer se encuentra en
el nodo referenciado por "find", la referencia "prev" se utiliza para indicar el nodo anterior (padre)
del que se pretende extraer, "node" es una copia de esta referencia y "temp" se utiliza para
localizar los nodos cuyos valores son menores al que se pretende retirar.
En el esquema (2) se muestra cmo se aplica la tcnica del mayor de los menores, de manera que
la referencia "temp" indica el nodo que contiene al mayor elemento de todos los menores al que
se pretende retirar.
En los siguientes pasos, esta tcnica ajusta los enlaces fusionando los subrboles de manera que
no se pierda el criterio de orden
En el esquema (3) se muestra cmo se "salva" todo el subrbol derecho del que se pretende
retirar, conectndolo como subrbol derecho del mayor de los menores.
En el esquema (4) se ajusta el valor de la referencia "node" que debe tomar el valor de su subrbol
izquierdo y luego se ajusta el valor de la referencia del nodo padre del que se va a extraer, esta
referencia se mantiene en la "prev" y debe apuntar al actual valor de "node".
Estructura de Datos y rboles
- 22 -
Por ltimo se anulan las referencias a los subrboles izquierdo y derecho de la referencia "find" de
ese modo el recolector de basura podr recuperar esa memoria y se obtiene el valor del elemento
almacenado en dicho nodo.
Por supuesto, el algoritmo debe verificar si la raz del rbol ha cambiado su valor para ajustarlo en
la estructura interna del rbol binario de bsqueda.

(3) primer ajuste de enlaces

(4) ajuste final de enlaces

Esta ltima tcnica, la "eliminacin por fusin" es ms rpida dado que utiliza menos variables y
pasos de cdigo sin embargo va dejando un rbol que cada vez tiene las ramas ms largas;
veremos en la siguiente publicacin que esto no es bueno.
La tcnica de "eliminacin por copia" a pesar de ser ms lenta y con ms pasos de cdigo deja un
rbol razonablemente parejo, con esto quiero decir que las ramas tanto izquierda como derecha
mantienen la forma del rbol original.
Implementacin de BinarySearchTree<ELEMENT>
A continuacin est toda la declaracin de la clase BinarySearchTree que estuvimos discutiendo,
en ella se muestran los mtodos que implementan ambas tcnicas para eliminar un nodo,
solamente se debe cambiar cul se desea utilizar en el mtodo Remove( ... ).
Queda para que los estudiantes realicen el mtodo de bsqueda de un elemento en particular,
recordemos que no se puede invocar al mtodo Remove( ... ) sin antes estar seguros que el
elemento existe en el rbol binario de bsqueda.
Estructura de Datos y rboles
- 23 -

using System;

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

#region Constructores (no se heredan)
/// <summary>
/// Constructor por defecto
/// </summary>
public BinarySearchTree()
: base()
{
}
/// <summary>
/// Constructor especializado que crea un rbol
/// binario de busqueda para el elemento indicado
/// </summary>
/// <param name="item">Elemento</param>
public BinarySearchTree(ELEMENT item)
: base(item)
{
}
#endregion

#region Comportamiento Agregar y Retirar elementos

/// <summary>
/// Agrega un elemento al rbol binario de bsqueda
/// </summary>
/// <param name="item">Elemento a agregar</param>
public void Add(ELEMENT item)
{
if (this.IsEmpty)
{
this.Root = new Node<ELEMENT>(item);
}
else
{
// Implementacin iterativa que busca la posicin
// para el nuevo elemento de acuerdo al criterio
// de comparacin que se establece en el mtodo
// CompareTo de cada Item
Node<ELEMENT> temp = this.Root, prev = null;
while (temp != null)
{
prev = temp;
if (temp.Item.CompareTo(item) > 0)
{
Estructura de Datos y rboles
- 24 -
temp = temp.Left;
}
else
{
temp = temp.Right;
}
}
// Implementacin que crea y agrega un nodo
// de acuerdo al criterio de comparacin que se
// establece en el mtodo CompareTo de cada Item
temp = new Node<ELEMENT>(item);
if (prev.Item.CompareTo(item) > 0)
{
prev.Left = temp;
}
else
{
prev.Right = temp;
}
}
}
/// <summary>
/// Extrae el elemento del rbol binario de busqueda
/// </summary>
/// <param name="item">Elemento a extraer</param>
public ELEMENT Remove(ELEMENT item)
{
return RemoveByCopy(item);
}
/// <summary>
/// Extrae el elemento del rbol binario de busqueda
/// implementando la eleiminacin por fusin
/// </summary>
/// <param name="item">Elemento a extraer</param>
protected ELEMENT RemoveByFusion(ELEMENT item)
{
Node<ELEMENT> find = this.Root, prev = null, node, temp;
while ((find != null) && (!find.Item.Equals(item)))
{ // bsqueda iterativa del nodo recordando al nodo padre
prev = find;
if (find.Item.CompareTo(item) < 0)
{
find = find.Right;
}
else
{
find = find.Left;
}
}
// se supone que en find tenemos el nodo a retirar
node = find;
if ((find != null) && (find.Item.Equals(item)))
{
if (node.Right == null) // no hay subrbol derecho
{
node = node.Left;
}
Estructura de Datos y rboles
- 25 -
else
{
if (node.Left == null) // no hay subrbol izquierdo
{
node = node.Right;
}
else
{ // aplicar la tcnica mayor de los menores
temp = node.Left; // (1) a la izquierda (los menores)
while (temp.Right != null) // (2) busca el mayor de los
menores
{
temp = temp.Right;
}
// (3) conectar la rama derecha del nodo que se retira
temp.Right = node.Right;
// (4) desconectar el nodo (queda en find)
node = node.Left;
}
}
// (5) ajustar todo el arbol
if (find == this.Root)
{
this.Root = node;
}
else
{
if (prev.Left == find)
{
prev.Left = node;
}
else
{
prev.Right = node;
}
}
}
if (find != null)
{
find.Left = find.Right = null;
return find.Item;
}
else // else no est o el rbol est vacio
{
throw new Exception("No existe el elemento o el rbol est
vacio");
}
}
/// <summary>
/// Extrae el elemento del rbol binario de busqueda
/// implementando la eleiminacin por copia
/// </summary>
/// <param name="item">Elemento a extraer</param>
protected ELEMENT RemoveByCopy(ELEMENT item)
{
Node<ELEMENT> find = this.Root, prev = null, node, temp;
while ((find != null) && (!find.Item.Equals(item)))
Estructura de Datos y rboles
- 26 -
{ // bsqueda iterativa del nodo recordando al nodo padre
prev = find;
if (find.Item.CompareTo(item) < 0)
{
find = find.Right;
}
else
{
find = find.Left;
}
}
// se supone que en find tenemos el nodo a retirar
node = find;
ELEMENT save = default(ELEMENT);
if (find != null)
{
save = find.Item;
}
if ((find != null) && (find.Item.Equals(item)))
{
if (node.Right == null) // no hay subrbol derecho
{
node = node.Left;
}
else
{
if (node.Left == null) // no hay subrbol izquierdo
{
node = node.Right;
}
else
{ // aplicar la tcnica mayor de los menores
temp = node.Left; // (1) a la izquierda (los menores)
Node<ELEMENT> last = node;
while (temp.Right != null) // (2) busca el mayor de los
menores
{
last = temp;
temp = temp.Right;
}
// (3) realiza la copia de contenidos
node.Item = temp.Item;
// (4) ajusta los enlaces
if (last == node)
{
last.Left = temp.Left;
}
else
{
last.Right = temp.Left;
}
temp.Left = null;
}
}
// (5) ajustar todo el arbol
if (find == this.Root)
{
Estructura de Datos y rboles
- 27 -
this.Root = node;
}
else
{
if (prev.Left == find)
{
prev.Left = node;
}
else
{
prev.Right = node;
}
}
}
if (find != null)
{
return save;
}
else // else no est o el rbol est vacio
{
throw new Exception("No existe el elemento o el rbol est
vacio");
}
}

#endregion
}
}
Cdigo para probar la implementacin
El siguiente cdigo sirve para probar la implementacin realizada:

using System;

namespace DemoArbol4
{
class Program
{
static void Main(string[] args)
{
BinarySearchTree<char> a = new BinarySearchTree<char>();

a.Add('S');
a.InOrder(); Console.WriteLine();
a.Add('B');
a.InOrder(); Console.WriteLine();
a.Add('Q');
a.InOrder(); Console.WriteLine();
a.Add('R');
a.InOrder(); Console.WriteLine();
a.Add('T');
a.InOrder(); Console.WriteLine();
a.Add('U');
a.InOrder(); Console.WriteLine();
a.Add('S');
Estructura de Datos y rboles
- 28 -
a.InOrder(); Console.WriteLine();
a.Add('A');
a.InOrder(); Console.WriteLine();
Console.WriteLine();

char x;
x = a.Remove('A');
a.InOrder();
Console.WriteLine("\nRetirado: {0}", x.ToString());

x = a.Remove('Q');
a.InOrder();
Console.WriteLine("\nRetirado: {0}", x.ToString());

x = a.Remove('S');
a.InOrder();
Console.WriteLine("\nRetirado: {0}", x.ToString());
}
}
}
La salida de este programa es la siguiente:

Conclusiones
Es un tema complejo, con algoritmos elaborados que se entienden mejor grficamente pero no
debemos olvidar que todos estos conceptos son la base para el procesamiento de grandes
volmenes informacin.

Вам также может понравиться