You are on page 1of 46

Arboles Binarios Objetivo: Dar una introduccin a los rboles y mostrar la forma de implementar un rbol binario, ya sea en una

estructura esttica (un vector) o dinmicamente (semejante a una lista ligada). Descripcin: A lo largo de la siguiente prctica se mostrarn algunos conceptos tiles para comprender que es y para que pudiera servir un rbol, adems de que se mostrarn dos pequeos ejemplos que muestran algunos ejemplos de utilidad para rboles binarios. Nota:
El presente documento es una pequea sntesis sobre rboles binarios. Se trata este tema porque estos representan una de las estructuras de datos ms importantes en computacin y estos pueden aplicarse para la solucin de una gran variedad de problemas, pero no muchas personas los ven como una buena solucin puesto que los consideran un tanto complejos. El objetivo del presente ser dejar claro que es un rbol binario y crear algunos ejemplos para tratar de tener una mayor comprensin. Y as despus cada uno de nosotros podamos definir si es conveniente aplicarlos a la solucin de algn problema o si alguna otra estructura de datos puede ser una mejor opcin. Puesto que solo veremos rboles las estructuras de datos alternativas corren por su cuenta :-)

Desarrollo:

Conceptos y Terminologa bsica


Si vamos a trabajar con rboles, lo primero que tenemos que ver es que es un rbol. Aqu tenemos algunas definiciones para rbol: - Un rbol es una estructura de datos no lineal y homognea en el que cada elemento puede tener varios elementos posteriores, pero tan slo puede tener un elemento anterior. - Es una estructura jerrquica aplicada sobre una coleccin de elementos u objetos llamados nodos; de los cuales uno es conocido como raz. Adems se crea una relacin o parentesco entre los nodos dando lugar a trminos como padre, hijo, hermano, antecesor, sucesor, ancestro, etc. - Un rbol es una estructura compuesta por un dato y varios rboles. Dado un nodo cualquiera de la estructura, podemos considerarlo como una estructura independiente. Es decir, un nodo cualquiera puede ser considerado como la raz de un rbol completo. - Son estructuras dinmicas no lineales. Dinmicas porque las estructuras de rbol pueden cambiar durante la ejecucin de un programa. No lineales, puesto que a cada elemento del rbol pueden seguirle varios elementos. En las estructuras de datos lineales cada elemento tiene un nico elemento anterior y un nico elemento posterior. El tipo de estructura ms general son los grafos. En un grafo cada elemento puede tener varios elementos anteriores y varios elementos posteriores. Los rboles no son ms que un tipo especial de grafo en el que cada elemento puede tener varios elementos posteriores, pero tan slo puede tener un elemento anterior. Tanto grafos como rboles son estructuras no lineales. Creo que la mayora, sino es que todos, hemos utilizado los rboles cuando hemos hecho un rbol genealgico o alguna estructura jerrquica de alguna organizacin. Y que me dicen de la forma en la que organizamos la informacin en nuestras maquinas (se hace en una estructura de directorios y subdirectorios en forma de rbol, para facilitar su bsqueda). Talvez sin darnos cuenta, pero hemos manejado el concepto de rbol .

Adems de la definicin debemos conocer otros conceptos bastante importantes, pues estos pudieran ser tiles a la hora de codificar un rbol: En relacin con otros nodos: Nodo padre. Nodo que contiene un puntero al nodo actual. En un rbol un nodo solo puede tener un nodo padre. X es padre de Y s y solo s el nodo X apunta a Y. Tambin se dice que X es antecesor de Y. En la Figura 1: B es padre de E y F. Nodo hijo. Cualquiera de los nodos apuntados por uno de los nodos del rbol. Un nodo puede tener varios hijos. X es hijo de Y, s y solo s el nodo X es apuntado por Y. Tambin se dice que X es descendiente directo de Y. En la Figura 1: E es hijo de B. Hermano. Dos nodos sern hermanos si son descendientes directos de un mismo nodo. En la Figura 1: E y F son hermanos. En cuanto a la posicin dentro del rbol: Nodo raz. Es el nico nodo del rbol que no tiene padre. Este es el nodo que usaremos para referirnos al rbol. En la Figura 1 A es el nodo raz. Nodo hoja. Nodo que no tiene hijos. Se le llama hoja o terminal a aquellos nodos que no tienen ramificaciones (hijos). En la Figura 1 N es un nodo hoja. Nodo interior. Es un nodo que no es raz ni hoja. En la Figura 1 D es un nodo interior. Existen otros conceptos que definen las caractersticas del rbol, en relacin a su tamao: Orden. Es el nmero potencial de hijos que puede tener cada elemento de rbol. De este modo, diremos que un rbol en el que cada nodo puede apuntar a otros dos es de orden dos, si puede apuntar a tres ser de orden tres, etc. Podramos decir que nuestro rbol de ejemplo (Figura 1) es de orden tres. Grado. El nmero de hijos que tiene el elemento con ms hijos dentro del rbol. En el rbol del ejemplo, el grado es tres, ya que tanto A como D tienen tres hijos, y no existen elementos con ms de tres hijos. Nivel. Se define para cada elemento del rbol como la distancia a la raz, medida en nodos. El nivel de la raz es cero, el de sus hijos uno y as sucesivamente. En el ejemplo, el nodo D tiene nivel 1, el nodo G tiene nivel 2, y el nodo N nivel 3. Altura. La altura de un rbol se define como el nivel del nodo de mayor nivel. Como cada nodo de un rbol puede considerarse a su vez como la raz de un rbol, tambin podemos hablar de altura de ramas; el mximo nmero de nodos que hay que recorrer para llegar de la raz a una de las hojas. El rbol de la Figura 1 tiene altura 3, la rama B tiene altura 2, la rama G tiene altura 1, la N cero... Peso. Es el nmero de nodos del rbol sin contar la raz. Camino. Es una secuencia de nodos, en el que dos nodos consecutivos cualesquiera son padre e hijo. En el ejemplo A-D-H y A-C-G-M son caminos. Longitud de camino. Es el nmero de arcos que deben ser recorridos para llegar desde la raz al nodo X. Por definicin la raz tiene longitud de camino 1, y sus descendientes directos longitud de camino 2 y as sucesivamente. En nuestro rbol de ejemplo G tiene longitud de camino 3 y N tiene longitud de camino 4. Rama. Es el camino desde el nodo raz a una hoja. En el ejemplo A-B-E-K y A-B-F son ramas.

Figura 1. rbol de grado tres Los rboles tienen una gran variedad de aplicaciones. Por ejemplo, se pueden utilizar para representar frmulas matemticas, para organizar adecuadamente la informacin, para construir un rbol genealgico, para el anlisis de circuitos elctricos, para numerar los captulos y secciones de un libro, etc. Bueno y como dijimos que lo que se vera aqu es rboles binarios pues yo creo que mejor nos vamos centrando en estos

rboles binarios
Los rboles de orden dos son bastante especiales. Estos rboles se conocen tambin como rboles binarios, ya que cada nodo del rbol no tendr ms de dos descendientes directos. Algunas definiciones pueden ser: 1. Un rbol binario es un rbol de grado 2 2. Un rbol binario es aquel que: a. Es vaco, b. Esta formado por un nodo cuyos subrboles izquierdo y derecho son a su vez rboles binarios.
N

Figura 2. Ejemplo de un rbol binario En alguna de las definiciones del inicio del documento, la tercera para ser precisos, se utiliza la recursin para definir un rbol porque representa la forma ms apropiada y porque adems es una caracterstica inherente de los mismos. En cualquier rbol, no slo en los binarios, si eliminamos el nodo raz, obtenemos dos rboles; en el caso de que sea un rbol binario. Aquel que colgaba del enlace izquierdo del nodo raz se denomina subrbol izquierdo y aquel que colgaba del enlace derecho se denomina subrbol derecho. Adems, en un rbol binario, todos los subrboles son tambin rboles binarios. De hecho, a partir de cualquier nodo de un rbol podemos definir un nuevo rbol sin ms que considerarlo como su nodo raz. Por tanto, cada nodo tiene asociados un subrbol derecho y uno izquierdo. 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 rbol binario equilibrado Es un rbol en el que en todos sus nodos se cumple la siguiente propiedad: | altura(subrbol_izquierdo) altura(subrbol_derecho) | 1
M

Figura 3. rbol equilibrado

Figura 4. rbol NO equilibrado

rbol binario completo Es un rbol en el que todos los nodos tienen dos hijos y todas las hojas estn en el mismo nivel. Se denomina completo porque cada nodo, excepto las hojas, tiene el mximo de hijos que puede tener.

Figura 5. rbol binario completo

Recorridos por rboles


Una de las cosas que debemos poder hacer con un rbol es poder movernos a travs de la informacin que este contiene. El modo evidente de moverse a travs de las ramas de un rbol es siguiendo las referencias de los nodos que las componen. Los recorridos dependen en gran medida del tipo y propsito del rbol, pero hay ciertos recorridos que usaremos frecuentemente. Se trata de aquellos recorridos que incluyen todo el rbol. Hay tres formas de recorrer un rbol completo, y las tres se suelen implementar mediante recursividad. En los tres casos se sigue siempre a partir de cada nodo todas las ramas una por una. Estos tres casos son: - Pre-orden - In-orden - Post-orden 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 N Q V 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 Q R V 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 Y como se que a la mayora de nosotros no nos agrada mucho la teora, aunque sea muy necesaria , pues vamos viendo algo prctico.

Implementaciones del rbol binario

Para poder implementar un rbol binario primero debemos definir la estructura de los nodos. Cada nodo del rbol estar formado por tres partes: La informacin contenida en el nodo, la cual puede ser un tipo primitivo o puede ser cualquier tipo de objeto Un enlace al hijo derecho (raz del subrbol derecho) Un enlace al hijo izquierdo (raz del subrbol izquierdo) Grficamente:
NODO Informacin Izq Der

Figura 6. Nodo de un rbol binario Frecuentemente, aunque tampoco es estrictamente necesario, para hacer ms fcil moverse a travs del rbol, aadiremos un puntero a cada nodo que apunte al nodo padre. De este modo podremos avanzar en direccin a la raz, y no slo hacia las hojas. Si implementamos este puntero nuestro nodo estara compuesto por cuatro partes: Un enlace al padre del nodo La informacin contenida en el nodo, la cual puede ser un tipo primitivo o puede ser cualquier tipo de objeto Un enlace al hijo derecho (raz del subrbol derecho) Un enlace al hijo izquierdo (raz del subrbol izquierdo) Grficamente:
NODO

Padre Informacin Izq Der

Figura 7. Nodo de un rbol binario con referencia hacia su padre Los rboles pueden ser construidos con estructuras estticas y dinmicas. Las estticas son arreglos, registros y conjuntos, mientras que las dinmicas estn representadas por listas.

Implementacin esttica de un rbol binario mediante un vector

Para realizar la implementacin esttica del rbol binario utilizamos una estrategia en la que simulamos la memoria dinmica mediante el uso de un vector. Cada registro contendr un nodo con los cuatro campos especificados anteriormente, en la Figura 7, y todos los nodos se almacenan en un vector. Para implementar los enlaces, en lugar de apuntadores, utilizaremos nmeros enteros que sern los ndices en el vector donde se encuentran: el padre, el hijo izquierdo y el hijo derecho. Una representacin de nuestra clase Nodo sera la siguiente:
org.neos.arboles.binarios.estaticos.bean::Nodo -informacion : Object -padre : int -derecho : int -izquierdo : int

Figura 8. Clase Nodo Y su definicin en Java sera la siguiente:


package org.neos.arboles.binarios.estaticos.beans; public class Nodo private int private int private int private int { informacion; padre; derecho; izquierdo;

public Nodo() { this.informacion = -1; this.derecho = -1; this.izquierdo = -1; } public Nodo(int informacion) { this.informacion = informacion; this.derecho = -1; this.izquierdo = -1; } public int getDerecho() { return derecho; } public int getIzquierdo() { return izquierdo; } public int getInformacion() { return informacion; } public void setDerecho(int derecho) { this.derecho = derecho; } public void setIzquierdo(int izquierdo) {

this.izquierdo = izquierdo;

public void setInformacion(int informacion) { this.informacion = informacion; } public boolean equals(Object nodo) { Nodo _nodo = (Nodo)nodo; Object info_nodo = _nodo.getInformacion(); return this.informacion.equals(info_nodo); } }

Como vemos nuestro nodo es una clase muy simple la cual tiene cuatro variables de instancia y los mtodos get y set de estas. Adicional a los mtodos get y set contiene un mtodo que nos ser til para saber si nuestro nodo es igual a otro nodo, este mtodo es: equals(Object), el cual estamos sobrescribiendo del mtodo que proporciona Object. Ya tenemos la clase con la cual podemos crear instancias de nuestros nodos, as que ahora vamos a implementar la clase que representar a nuestro rbol Ahh pero antes de eso Adems utilizaremos una especie de Wrapper para la informacin que contendr cada nodo del rbol. Pero los nodos no contendrn objetos del Wrapper este solo nos ser til para cuando hagamos comparaciones entre la informacin de los nodos. Perdn, pero fue la nica forma que se me ocurri para hacer independiente la informacin de la estructura del rbol. As no tenemos que modificar el cdigo del rbol si queremos que este almacene otro tipo de informacin Aunque tendamos que redefinir nuestro Wrapper Bueno pues pasemos a ver nuestro Wrapper para la informacin que almacenar nuestro rbol. Para este ejemplo solo vamos a almacenar cadenas (pero solo para poder representar rboles como los que vimos en los ejemplos de la teora). De modo que quedara de la siguiente forma.
org.neos.arboles.binarios.estaticos.bean::Informacion -contenido : String +equals(in info : Object) : Boolean +compareTo info : Object) : int (in

Figura 9. Wrapper para la informacin que almacenar el rbol Tericamente, para poder trabajar con otro tipo de informacin lo nico que debemos cambiar es el tipo de la propiedad contenido y hacer que compareTo se haga la comparacin de forma correcta y en el constructor y el set de la informacin se haga el cast al tipo correcto, con respecto al tipo de la variable contenido, ya lo nico que no sabe el rbol es como comparar la informacin que contendrn sus nodos, puesto que esta puede ser de cualquier tipo. El rbol que implementaremos permitir las siguientes operaciones: - insertar elementos - borrar elementos - recorrer el rbol (preorden, inorden y postorden)

Obtener el peso del rbol o una rama (mediante la posicin del nodo, en el vector) Obtener el nmero de nodos del rbol o una rama (mediante la posicin del nodo, en el vector) Obtener la altura de rbol o una rama (mediante la posicin del nodo, en el vector)

Adems ser un rbol ordenado; es decir, el hijo izquierdo de un nodo debe ser menor y el hijo derecho debe ser mayor al hijo izquierdo y al nodo. El campo que es importante conservar siempre es el nodo raz, ya que es el nodo a partir del cual se desarrolla el rbol y si perdemos este nodo perdemos el acceso a todo el rbol. En nuestro caso tendremos dos variables ms dentro de nuestro rbol: el vector en el que se almacenarn los nodos de nuestro rbol y una arreglo (ArrayList) en el que almacenaremos los recorridos del rbol. De modo que la clase que representa nuestro rbol quedar de la siguiente forma:
org.neos.arboles.binarios.estaticos::ArbolBinarioEstatico -arbol : Nodo[] -posicion_raiz : int -recorrido : ArrayList +ArbolBinarioEstatico(in num_elementos : int) : Nodo +esArbolVacio() : Boolean +obtenerPosicionRaiz() : int -obtenerPosicionElemento(in info : String, in posicion _actual : int) : int +obtenerPosicionElemento(in info : String) : int +existeElemento(in info : String) : Boolean +obtenerElemento(in info : String) : ArbolBinarioEstatico +obtenerNumeroElementos posicion : int) : int (in +obtenerPeso(in raiz : int) : int +obtenerAltura(in raiz : int) : int +obtenerCapacidadArbol() : int -obtenerPosicionLibre() : int -insertarElemento(in nuevo_nodo : ArbolBinarioEstatico, in posicion_actual : int) : Boolean -insertarElemento(in info : String, in posicion _actual : int) : Boolean +insertarElemento(in info : String) : Boolean -borrarNodoHoja nodo : ArbolBinarioEstatico, in posicion _nodo : int) : Boolean (in -borrarNodoInterior in nodo : ArbolBinarioEstatico, in posicion _nodo : int) : Boolean ( -borrarNodoRaiz nodo : ArbolBinarioEstatico, in posicion_nodo : int) : Boolean (in +borrarElemento info : String) : Boolean (in +recorridoPreorden posicion : int) : ArrayList (in +recorridoInorden posicion : int) : ArrayList (in +recorridoPostorden posicion : int) : ArrayList (in

Figura 9. Clase para el rbol contenido en un vector Como podemos darnos cuenta nuestro rbol tiene varios mtodos, donde algunos de estos son privados y otros pblicos. A continuacin veremos una descripcin de estos mtodos:

Mtodos pblicos
public ArbolBinarioEstatico(int num_elementos) throws ExceptionDimensionInvalida

Constructor que permite crear un rbol contenido en un vector de un tamao definido. Parmetros: - num_elementos: Nmero de elementos que podr contener el vector. Throws: - ExceptionDimensionInvalida: En caso de que el tamao del vector no sea valido.
public boolean esArbolVacio()

Mtodo til para preguntar es nuestro rbol esta vaco o no. Return: - true cuando el rbol no contiene elementos. - false cuando el rbol contiene elementos.
public int obtenerPosicionRaiz()

Obtener la posicin del nodo raz, dentro del vector. Return: Posicin del elemento que representa al nodo raz. Se obtiene -1 (NULL) si el rbol esta vaco.
public int obtenerPosicionElemento(Object info) throws ArrayIndexOutOfBoundsException

Buscar un elemento en base a la informacin que contienen los elementos del rbol. Parmetros: - info: Informacin que contiene el elemento que se esta buscando. Return: Posicin del elemento del vector que contiene la informacin indicada. Throws: - ArrayIndexOutOfBoundsException: Si la posicin del elemento a buscar es -1. El nodo al que se apunta (ya sea izquierdo o derecho) antes de llamar a esta funcin es nulo (NULL).
public boolean existeElemento(Object info)

Obtener respuesta a la pregunta Existe el elemento en el rbol? Parmetros: - Informacin: a buscar dentro del rbol. Return: - true cuando un elemento en el rbol contiene la informacin especificada. - false cuando ningn elemento en el rbol contiene la informacin especificada.

public Nodo obtenerElemento(Object info)

Obtener el elemento (Nodo) que contiene la informacin indicada. Parmetros: - info: Informacin que se busca dentro del rbol. Return: - elemento que contiene la infoemacin, cuando la informacin existe dentro del rbol. - null, cuando la informacin especificada no existe dentro del rbol.
public int obtenerNumeroElementos(int posicion)

Obtener el nmero de elementos que contiene una rama especificada. Parmetros: - posicion: Posicin del elemento para el que se cuenta el nmero de nodos que cuelgan de l. Return: Nmero de nodos que cuelgan del nodo indicado.
public int obtenerPeso(int raiz)

Obtener el peso del rbol o una rama especificada. Que sera algo as como contar el nmero de nodos que cuelgan a la izquierda y derecha del nodo. Parmetros: - raiz: Posicin, dentro del vector, del nodo que se toma como raz. Return: Peso del rbol o rama especificada.
public int obtenerAltura(int raiz)

Obtener la altura de un rbol o rama de un rbol binario. La altura de un rbol se define como el nivel del nodo de mayor nivel Parmetros: - raiz: Posicin del elemento que es la raz del rbol o subrbol. Return: Altura del rbol o rama.
public int obtenerCapacidadArbol()

Obtener el nmero de elementos que puede almacenar el rbol. Return Nmero de elementos que puede almacenar el rbol.
public boolean insertarElemento(Object info) throws ExceptionDesbordamientoVector, ExceptionElementoDuplicado

Comprobar si se puede crear e insertar un nuevo elemento con la informacin indicada. Parmetros: - info: Informacin que contendr el nuevo elemento, si es que este puede ser insertado. Return: La respuesta a la pregunta Se inserto el elemento? Throws: - ExceptionDesbordamientoVector: Si el vector que representa el rbol ya esta lleno. - ExceptionElementoDuplicado: Si la informacin que se quiere insertar ya existe dentro del rbl.
public boolean borrarElemento(Object info) throws ExceptionNoEncontrado

Borrar un elemento del rbol. Parmetros: - info: Elemento que quiere eliminarse. Return: Respues ta a la pregunta Se borro el elemento? Throws: - ExceptionNoEncontrado: Si el elemento especificado no existe dentro del rbol.
public String recorridoPreorden(int posicion)

Recorrido (Nodo, Izquierda, Derecha) Parmetros: - posicion: Posicin a partir de la cual se comienza el recorrido. Return: Arreglo que contiene el recorrido del rbol.
public String recorridoInorden(int posicion)

Recorrido (Izquierda, Nodo, Derecha) Parmetros: - posicion: Posicin apartir de la cual se comienza el recorrido. Return: Arreglo que contiene el recorrido del rbol.
public String recorridoPostorden(int posicion)

Recorrido (Izquierda, Derecha, Nodo) Parmetros: - posicion: Posicin apartir de la cual se comienza el recorrido.

Return: Arreglo que contiene el recorrido del rbol. Mtodos privados


private int obtenerPosicionElemento(Object info, int posicion_actual) throws ArrayIndexOutOfBoundsException

Buscar un elemento recorriendo los elementos del rbol. Parmetros: - info: Informacin que contiene el elemento que se esta buscando. - posicion_actual: Posicin del elemento actual, con el que se compara la informacin. Return: Posicin del elemento del vector que contiene la informacin indicada. Throws: - ArrayIndexOutOfBoundsException: Si la posicin del elemento a buscar es -1. El nodo al que se apunta (ya sea izquierdo o derecho) antes de llamar a esta funcin es nulo (NULL).
private int obtenerPosicionLibre()

Buscar dentro del vector que representa el rbol una casilla que este libre o vaca. Return: Posicin del vector que no contiene un nodo.
private boolean insertarElemento(Object info, int posicion_actual)

Mtodo de apoyo a InsertarElemento(int). Este mtodo se encarga de agregar el elemento dentro del vector que representa el rbol. Parmetros: - info: Informacin que contendr el nuevo nodo. - posicion_actual: Posicin del nodo contra el que se compara la informacin. Return: La respuesta a la pregunta Se inserto el elemento?
private boolean insertarElemento(Nodo nuevo_nodo, int posicion_actual)

Mtodo de apoyo a InsertarElemento(int). Este mtodo se encarga de agregar el elemento dentro del vector que representa el rbol. Parmetros: - nuevo_nodo: Infrmacin que contendr el nuevo nodo. - posicion_actual: Posicin del nodo contra el que se compara la informacin. Return: La respuesta a la pregunta Se inserto el elemento?

private boolean borrarNodoInterior(Nodo nodo, int posicion_nodo)

Borrar un nodo interior, tiene por lo menos una rama y no es el noso raz del rbol. Parmetros: - nodo: Nodo que se quiere borrar. - posicion_nodo: Posicin del nodo a borrar, en el vector. Return: Respuesta a la pregunta Se borro el nodo?
private boolean borrarNodoHoja(Nodo nodo, int posicion_nodo)

Borrar un nodo que es una hoja. Parmetros: - nodo: Nodo a borrar. - posicion_nodo: Posicin, en el vector, del nodo a borrar. Return: Respuesta a la pregunta Se borro el nodo?
private boolean borrarNodoRaiz(Nodo nodo, int posicion_nodo)

Borrar el nodo que es la raz del rbol. Parmetros: - nodo: Nodo a borrar. - posicion_nodo: Posicin del nodo dentro del vector. Return: Respuesta a la pregunta Se borro el nodo? Definicin de la clase que representa el rbol:
package org.neos.arboles.binarios.estaticos; import java.util.ArrayList; import import import import import import org.neos.arboles.binarios.estaticos.beans.Informacion; org.neos.arboles.binarios.estaticos.beans.Nodo; org.neos.arboles.binarios.estaticos.constantes.ConstantesArbolBinarioEstatico; org.neos.arboles.binarios.estaticos.exceptions.ExceptionDesbordamientoVector; org.neos.arboles.binarios.estaticos.exceptions.ExceptionDimensionInvalida; org.neos.arboles.binarios.estaticos.exceptions.ExceptionElementoDuplicado;

import org.neos.arboles.binarios.estaticos.exceptions.ExceptionNoEncontrado; public class ArbolBinarioEstatico implements ConstantesArbolBinarioEstatico { private Nodo[] arbol; private int posicion_raiz; private ArrayList recorrido; public ArbolBinarioEstatico(int num_elementos) throws ExceptionDimensionInvalida { if(num_elementos <= 0) { String msg = "La dimension no puede ser cero o negativa!!"; throw new ExceptionDimensionInvalida(msg); } else { this.arbol = new Nodo[num_elementos]; } this.posicion_raiz = NULL; this.recorrido = null; } public boolean esArbolVacio() { return (NULL == posicion_raiz) ? true : false; } public int obtenerPosicionRaiz() { return posicion_raiz; } { private int obtenerPosicionElemento(Object info, int posicion_actual) throws ArrayIndexOutOfBoundsException Nodo nodo = arbol[posicion_actual]; Informacion obj_info = new Informacion(info); Informacion obj_info_pa = new Informacion( nodo.getInformacion() ); if( obj_info_pa.equals(obj_info) ) { return posicion_actual; } else if( obj_info_pa.compareTo(obj_info) > 0 ) { return obtenerPosicionElemento(info, nodo.getIzquierdo()); } else { return obtenerPosicionElemento(info, nodo.getDerecho()); }

public int obtenerPosicionElemento(Object info) throws ArrayIndexOutOfBoundsException { Nodo nodo_raiz = arbol[posicion_raiz];

Informacion obj_info = new Informacion(info); Informacion obj_info_r = new Informacion( nodo_raiz.getInformacion() ); if( obj_info_r.equals(obj_info) ) { return posicion_raiz; } else if( obj_info_r.compareTo(obj_info) > 0 ) { return obtenerPosicionElemento(info, nodo_raiz.getIzquierdo()); } else { return obtenerPosicionElemento(info, nodo_raiz.getDerecho()); } } public boolean existeElemento(Object info) { boolean respuesta = false; int posicion_elemento = -1; try { posicion_elemento = obtenerPosicionElemento(info); respuesta = true; } catch(ArrayIndexOutOfBoundsException aioob_e) { respuesta = false; } return respuesta;

public Nodo obtenerElemento(Object info) { int posicion_elemento = -1; Nodo elemento = null; try { posicion_elemento = obtenerPosicionElemento(info); elemento = arbol[posicion_elemento]; } catch(ArrayIndexOutOfBoundsException aioob_e) { ; } } return elemento;

public int obtenerNumeroElementos(int posicion) { int num_elems = 0; if(NULL != posicion) {

Nodo nodo = arbol[posicion]; num_elems += obtenerNumeroElementos(nodo.getIzquierdo()); num_elems++; num_elems += obtenerNumeroElementos(nodo.getDerecho()); } } return (num_elems);

public int obtenerPeso(int raiz) { int peso = 0; Nodo nodo = null; int num_h_izq = 0; int num_h_der = 0; if(NULL != raiz) { nodo = arbol[raiz]; num_h_izq = obtenerNumeroElementos(nodo.getIzquierdo()); num_h_der = obtenerNumeroElementos(nodo.getDerecho()); peso = num_h_izq + num_h_der; } } return peso;

public int obtenerAltura(int raiz) { int altura = 0; Nodo nodo = null; int ref_h_izq; int ref_h_der; int altura_r_izq = 0; int altura_r_der = 0; if(NULL != raiz) { altura = 1; nodo = arbol[raiz]; ref_h_izq = nodo.getIzquierdo(); ref_h_der = nodo.getDerecho(); if( (ref_h_izq != NULL) && (ref_h_der != NULL) ) {

altura_r_izq = obtenerAltura(ref_h_izq); altura_r_der = obtenerAltura(ref_h_der); if(altura_r_izq >= altura_r_der) { altura += altura_r_izq; } else { altura += altura_r_der; } } else if( (ref_h_izq != NULL) && (ref_h_der == NULL) ) { altura += obtenerAltura(ref_h_izq); } else if( (ref_h_izq == NULL) && (ref_h_der != NULL) ) { altura += obtenerAltura(ref_h_der); } else if( (ref_h_izq == NULL) && (ref_h_der == NULL) ) { altura -= 1; } } } return altura;

public int obtenerCapacidadArbol() { return arbol.length; } private int obtenerPosicionLibre() { int i, longitud = arbol.length; for(i = 0; i < longitud; i++) { if(null == arbol[i]) { return i; } } return NULL; } private boolean insertarElemento(Object info, int posicion_actual) { Nodo nodo = arbol[posicion_actual]; Nodo nuevo_nodo = null; int posicion = NULL; Informacion obj_info = new Informacion(info); Informacion obj_info_pa = new Informacion( nodo.getInformacion() ); if( obj_info_pa.compareTo(obj_info) > 0 ) { if(nodo.getIzquierdo() == NULL) {

posicion = obtenerPosicionLibre(); nodo.setIzquierdo(posicion); nuevo_nodo = new Nodo(info); nuevo_nodo.setPadre(posicion_actual); arbol[posicion] = nuevo_nodo; return true; } else { return insertarElemento(info, nodo.getIzquierdo()); } } else { if(nodo.getDerecho() == NULL) { posicion = obtenerPosicionLibre(); nodo.setDerecho(posicion); nuevo_nodo = new Nodo(info); nuevo_nodo.setPadre(posicion_actual); arbol[posicion] = nuevo_nodo; return true; } else { return insertarElemento(info, nodo.getDerecho()); } } }

public boolean insertarElemento(Object info) throws ExceptionDesbordamientoVector, ExceptionElementoDuplicado { Nodo nuevo_nodo = null; boolean se_inserto = false; if( this.esArbolVacio() ) { nuevo_nodo = new Nodo(info); arbol[0] = nuevo_nodo; this.posicion_raiz = 0; se_inserto = true; } else { if(obtenerNumeroElementos(posicion_raiz) == arbol.length) { throw new ExceptionDesbordamientoVector("El rbol esta lleno, no pueden agregarse ms elementos!!");

rbol!!");

} else { if( existeElemento(info) ) { throw new ExceptionElementoDuplicado("El elemento ya existe dentro del } else { se_inserto = insertarElemento(info, posicion_raiz); }

} } }

return se_inserto;

public boolean borrarElemento(Object info) throws ExceptionNoEncontrado { Nodo nodo = null; int posicion_elem = NULL; boolean se_borro = false; Nodo nodo_padre = null; Nodo nodo_aux = null; int posicion_aux = NULL; if( this.esArbolVacio() ) { throw new ExceptionNoEncontrado("El rbol esta vaco!!"); } else { if( existeElemento(info) ) { posicion_elem = obtenerPosicionElemento(info); nodo = arbol[posicion_elem]; if(nodo.getPadre() != NULL) { // Si no es el nodo raiz if( (nodo.getIzquierdo() != NULL) || (nodo.getDerecho() != NULL) ) { se_borro = borrarNodoInterior(nodo, posicion_elem); } else { se_borro = borrarNodoHoja(nodo, posicion_elem); } } else { se_borro = borrarNodoRaiz(nodo, posicion_elem); } } else { throw new ExceptionNoEncontrado("El elemento no existe dentro del rbol!!"); } } return se_borro;

} private boolean insertarElemento(Nodo nuevo_nodo, int posicion_actual) { Nodo nodo = arbol[posicion_actual]; int posicion = NULL; Informacion obj_info = new Informacion( nuevo_nodo.getInformacion() ); Informacion obj_info_pa = new Informacion( nodo.getInformacion() ); if( obj_info_pa.compareTo(obj_info) > 0 ) { if(nodo.getIzquierdo() == NULL) { posicion = obtenerPosicionLibre(); nodo.setIzquierdo(posicion); nuevo_nodo.setPadre(posicion_actual); arbol[posicion] = nuevo_nodo; return true; } else { return insertarElemento(nuevo_nodo, nodo.getIzquierdo()); } } else { if(nodo.getDerecho() == NULL) { posicion = obtenerPosicionLibre(); nodo.setDerecho(posicion); nuevo_nodo.setPadre(posicion_actual); arbol[posicion] = nuevo_nodo; return true; } else { return insertarElemento(nuevo_nodo, nodo.getDerecho()); } } }

private boolean borrarNodoInterior(Nodo nodo, int posicion_nodo) { boolean respuesta = false; Nodo nodo_padre = null; Nodo nodo_aux = null; int posicion_aux = NULL; int posicion_ins = NULL; if( (nodo.getIzquierdo() != NULL) && (nodo.getDerecho() != NULL) ) {

nodo_padre = arbol[nodo.getPadre()]; posicion_aux = nodo.getIzquierdo(); nodo_aux = arbol[posicion_aux]; posicion_ins = nodo.getDerecho(); if(nodo_padre.getIzquierdo() == posicion_nodo) { nodo_padre.setIzquierdo( nodo.getDerecho() ); } else { nodo_padre.setDerecho( nodo.getDerecho() ); } nodo = new Nodo(nodo_aux.getInformacion()); nodo.setDerecho(nodo_aux.getDerecho()); nodo.setIzquierdo(nodo_aux.getIzquierdo()); arbol[posicion_nodo] = null; arbol[posicion_aux] = null; insertarElemento(nodo, posicion_ins); respuesta = true; } else if(nodo.getIzquierdo() != NULL) { nodo_padre = arbol[nodo.getPadre()]; if(posicion_nodo == nodo_padre.getDerecho()) { nodo_padre.setDerecho( nodo.getIzquierdo() ); } else { nodo_padre.setIzquierdo( nodo.getIzquierdo() ); } arbol[posicion_nodo] = null; respuesta = true; } else { nodo_padre = arbol[nodo.getPadre()]; if(posicion_nodo == nodo_padre.getDerecho()) { nodo_padre.setDerecho( nodo.getDerecho() ); } else { nodo_padre.setIzquierdo( nodo.getDerecho() ); } arbol[posicion_nodo] = null; respuesta = true;

} return respuesta;

} private boolean borrarNodoHoja(Nodo nodo, int posicion_nodo) { boolean se_borro = false; Nodo nodo_padre = null; nodo_padre = arbol[nodo.getPadre()]; if(posicion_nodo == nodo_padre.getDerecho()) { nodo_padre.setDerecho(NULL); } else { nodo_padre.setIzquierdo(NULL); } arbol[posicion_nodo] = null; se_borro = true; return se_borro; } private boolean borrarNodoRaiz(Nodo nodo, int posicion_nodo) { boolean se_borro = false; Nodo nodo_aux = null; int posicion_aux = NULL; if( (nodo.getIzquierdo() != NULL) && (nodo.getDerecho() != NULL) ) { this.posicion_raiz = nodo.getDerecho(); nodo_aux = arbol[posicion_raiz]; nodo_aux.setPadre(NULL); posicion_aux = nodo.getIzquierdo(); nodo_aux = arbol[posicion_aux]; nodo = new Nodo(nodo_aux.getInformacion()); nodo.setDerecho(nodo_aux.getDerecho()); nodo.setIzquierdo(nodo_aux.getIzquierdo()); arbol[posicion_nodo] = null; arbol[posicion_aux] = null; insertarElemento(nodo, posicion_raiz); se_borro = true; } else if(nodo.getIzquierdo() != NULL) { this.posicion_raiz = nodo.getIzquierdo(); nodo_aux = arbol[posicion_raiz]; nodo_aux.setPadre(NULL);

arbol[posicion_nodo] = null; se_borro = true; } else if(nodo.getDerecho() != NULL) { this.posicion_raiz = nodo.getDerecho(); nodo_aux = arbol[posicion_raiz]; nodo_aux.setPadre(NULL); arbol[posicion_nodo] = null; se_borro = true; } else { // no tiene ramas arbol[posicion_raiz] = null; posicion_raiz = NULL; se_borro = true; } return se_borro; } public ArrayList recorridoPreorden(int posicion) { if(posicion == posicion_raiz) { recorrido = new ArrayList(); } if(NULL != posicion) { Nodo nodo = arbol[posicion]; recorrido.add(nodo.getInformacion()); recorridoPreorden(nodo.getIzquierdo()); recorridoPreorden(nodo.getDerecho()); } return recorrido; } public ArrayList recorridoInorden(int posicion) { if(posicion == posicion_raiz) { recorrido = new ArrayList(); } if(NULL != posicion) { Nodo nodo = arbol[posicion]; recorridoInorden(nodo.getIzquierdo()); recorrido.add(nodo.getInformacion()); recorridoInorden(nodo.getDerecho()); }

return recorrido;

public ArrayList recorridoPostorden(int posicion) { if(posicion == posicion_raiz) { recorrido = new ArrayList(); } if(NULL != posicion) { Nodo nodo = arbol[posicion]; recorridoPostorden(nodo.getIzquierdo()); recorridoPostorden(nodo.getDerecho()); recorrido.add(nodo.getInformacion()); } return recorrido;

} }

Y un pequeo ejemplo en el que se muestra las funciones ms importantes de nuestro rbol:


package org.neos.arboles.binarios.estaticos; import java.util.ArrayList; import import import import org.neos.arboles.binarios.estaticos.exceptions.ExceptionDesbordamientoVector; org.neos.arboles.binarios.estaticos.exceptions.ExceptionDimensionInvalida; org.neos.arboles.binarios.estaticos.exceptions.ExceptionElementoDuplicado; org.neos.arboles.binarios.estaticos.exceptions.ExceptionNoEncontrado;

public class Ejemplo { public static void main(String[] args) throws ExceptionDimensionInvalida { ArbolBinarioEstatico arbol = new ArbolBinarioEstatico(27); ArrayList recorrido = null; int i, num_elems; try { arbol.insertarElemento("G"); arbol.insertarElemento("E"); arbol.insertarElemento("N"); arbol.insertarElemento("D"); arbol.insertarElemento("J");

arbol.insertarElemento("F"); arbol.insertarElemento("O"); arbol.insertarElemento("Q"); recorrido = arbol.recorridoPreorden(arbol.obtenerPosicionRaiz()); System.out.print("Recorrido Preorden: "); num_elems = recorrido.size(); for(i = 0; i < num_elems; i++) { System.out.print(recorrido.get(i) + " - "); } recorrido = arbol.recorridoInorden(arbol.obtenerPosicionRaiz()); System.out.print("\nRecorrido Inorden: "); num_elems = recorrido.size(); for(i = 0; i < num_elems; i++) { System.out.print(recorrido.get(i) + " - "); } recorrido = arbol.recorridoPostorden(arbol.obtenerPosicionRaiz()); System.out.print("\nRecorrido Postorden: "); num_elems = recorrido.size(); for(i = 0; i < num_elems; i++) { System.out.print(recorrido.get(i) + " - "); } System.err.println("\nNumero de elementos: "+arbol.obtenerNumeroElementos(arbol.obtenerPosicionRaiz())); System.err.println("Peso del rbol: "+arbol.obtenerPeso(arbol.obtenerPosicionRaiz())); System.err.println("Altura del rbol: "+arbol.obtenerAltura(arbol.obtenerPosicionRaiz())); // Borrar un elemento de nustro rbol (un nodo interior) arbol.borrarElemento("N"); recorrido = arbol.recorridoPreorden(arbol.obtenerPosicionRaiz()); System.out.print("\nRecorrido Preorden: "); num_elems = recorrido.size(); for(i = 0; i < num_elems; i++) { System.out.print(recorrido.get(i) + " - "); } recorrido = arbol.recorridoInorden(arbol.obtenerPosicionRaiz()); System.out.print("\nRecorrido Inorden: "); num_elems = recorrido.size(); for(i = 0; i < num_elems; i++) { System.out.print(recorrido.get(i) + " - "); }

recorrido = arbol.recorridoPostorden(arbol.obtenerPosicionRaiz()); System.out.print("\nRecorrido Postorden: "); num_elems = recorrido.size(); for(i = 0; i < num_elems; i++) { System.out.print(recorrido.get(i) + " - "); } System.err.println("\nNumero de elementos: "+arbol.obtenerNumeroElementos(arbol.obtenerPosicionRaiz())); System.err.println("Peso del rbol: "+arbol.obtenerPeso(arbol.obtenerPosicionRaiz())); System.err.println("Altura del rbol: "+arbol.obtenerAltura(arbol.obtenerPosicionRaiz())); } catch(ExceptionElementoDuplicado ed_e) { System.err.println(ed_e.getMessage()); } catch(ExceptionDesbordamientoVector dv_e) { System.err.println(dv_e.getMessage()); } catch(ExceptionNoEncontrado ne_e) { System.err.println(ne_e.getMessage()); } } }

Con las instrucciones del inicio de nuestro pequeo ejemplo (hasta antes de la marca de borrar un elemento) se crea un rbol como el mostrado en la siguiente figura:
G

Figura 10. rbol construido con el programa ejemplo.

Y las instrucciones System.out.print que estn antes de la marca de borrar elemento nos ayudan a comprobar que lo que se muestra en la Figura 11 es cierto. Lo que deben desplegar las instrucciones hasta antes de la marca de borrar elemento es:
Recorrido Preorden: Recorrido Inorden: Recorrido Postorden: Numero de elementos: Peso del rbol: Altura del rbol: G - E - D - F - N - J - O - Q D - E - F - G - J - N - O - Q D - F - E - J - Q - O - N - G 8 7 3

Despus de la marca borrar elemento, la estructura de nuestro rbol cambia a la mostrada en la siguiente figura:
G

Figura 12. rbol despus de borrar el elemento N del rbol de la Figura 11. Y las instrucciones System.out.print que estn despues de la marca de borrar elemento nos ayudan a comprobar que lo que se muestra en la Figura 12 es cierto. Lo que deben desplegar las instrucciones despues de la marca de borrar elemento es:
Borrar elemento "N": Recorrido Preorden: Recorrido Inorden: Recorrido Postorden: Numero de elementos: Peso del rbol: Altura del rbol: G - E - D - F - O - J - Q D - E - F - G - J - O - Q D - F - E - J - Q - O - G 7 6 2

Y como fue a m a quien se le ocurri la brillante idea de poner el Wrapper para la informacin que contienen los nodos pues vamos a ver un ejemplo en donde nuestro nodo va a contener un objeto Persona, el cual vamos a definir aqu. La definicin de nuestra clase persona sera la que se muestra en la Figura 13.
org.neos.beans::Persona -nombre : Nombre -direccion : Direccion -telefono : String

Figura 13. Clase Persona Esta clase esta compuesta por un nombre (clase org.beans.Nombre), una direccin (clase org.neos.beans.Direccion) y un atributo cadena llamado telefono. El cdigo de estas clases es: Clase org.neos.beans.Nombre:
package org.neos.beans; public class Nombre { private String nombre;

private String paterno; private String materno; public Nombre(String nombre, String paterno, String materno) { this.nombre = nombre; this.paterno = paterno; this.materno = materno; } public String getMaterno() { return materno; } public String getNombre() { return nombre; } public String getPaterno() { return paterno; } public void setMaterno(String string) { materno = string; } public void setNombre(String string) { nombre = string; } public void setPaterno(String string) { paterno = string; } public boolean equals(Object nombre) { Nombre _nombre = (Nombre)nombre; if( this.nombre.equals(_nombre.getNombre() ) && paterno.equals(_nombre.getPaterno() ) && materno.equals(_nombre.getMaterno() ) ) { return true; } else { return false; }

public int compareTo(Object nombre) { Nombre _nombre = (Nombre)nombre; String nom = _nombre.getNombre(); String a_pat = _nombre.getPaterno(); String a_mat = _nombre.getMaterno(); int com_ap = paterno.compareTo(a_pat); if(com_ap == 0) { com_ap = materno.compareTo(a_mat); if(com_ap == 0) { return this.nombre.compareTo(nom); } else { return com_ap; } } else { return com_ap; }

} }

Clase org.neos.beans.Direccion:
package org.neos.beans; public class Direccion { private String calle; private int numero; private String interior; private String colonia; private String poblacion; private String cp; public Direccion(String calle, int num, String interior, String col, String pob, String cp) { this.calle = calle; this.numero = num; this.interior = interior; this.colonia = col; this.poblacion = pob; this.cp = cp; } public String getColonia() { return colonia; } public String getCp() { return cp; } public String getInterior() { return interior; } public int getNumero() { return numero; } public String getPoblacion() { return poblacion; } public void setColonia(String string) { colonia = string; } public void setCp(String string) { cp = string; } public void setInterior(String string) { interior = string; } public void setNumero(int i) { numero = i; } public void setPoblacion(String string) { poblacion = string; } }

Clase org.neos.beans.Direccion:
package org.neos.beans; public class Persona {

private Nombre nombre; private Direccion direccion; private String telefono; public Persona(Nombre nombre, Direccion direccion, String telefono) { this.nombre = nombre; this.direccion = direccion; this.telefono = telefono; } public Direccion getDireccion() { return direccion; } public Nombre getNombre() { return nombre; } public String getTelefono() { return telefono; } public void setDireccion(Direccion direccion) { this.direccion = direccion; } public void setNombre(Nombre nombre) { this.nombre = nombre; } public void setTelefono(String string) { telefono = string; } public boolean equals(Object persona) { Persona _persona = (Persona)persona; return nombre.equals(_persona.getNombre() ); } public int compareTo(Object persona) { Persona _persona = (Persona)persona; return nombre.compareTo(_persona.getNombre() ); } public String toString() { String respuesta = nombre.getPaterno() + " " + nombre.getMaterno() + ", " + nombre.getNombre(); } } return respuesta;

Ahora lo nico que tenemos que hacer es adaptar nuestra Clase org.neos.arboles.binarios.estaticos.beans.Informacion para que su contenido sea un objeto de tipo org.neos.beans.Persona:
package org.neos.arboles.binarios.estaticos.beans; import org.neos.beans.Persona; public class Informacion { private Persona contenido;

public Informacion(Object contenido) { this.contenido = (Persona)contenido; } public Object getContenido() { return contenido; } public void setContenido(Object contenido) { this.contenido = (Persona)contenido; } public boolean equals(Object info) { Informacion _info = (Informacion)info; if( contenido.equals(_info.getContenido()) ) { return true; } else { return false; }

public int compareTo(Object info) { Informacion _info = (Informacion)info; } } return contenido.compareTo(_info.getContenido());

Como podemos darnos cuenta lo que tenemos que hacer si queremos cambiar el contenido de nuestro rbol es definir la clase que nos dar la estructura de la informacin que queremos contener en nuestro rbol, junto con sus mtodos equals(Object) y compareTo(Object) (as como se hizo aqu con persona). Y ya que se tenga definida la clase de nuestra informacin se debe importar esta en la clase org.neos.arboles.binarios.estaticos.beans.Informacion y cambiar el tipo de nuestro contenido y el cast de este (Lo que se encuentra marcado con amarillo en el codigo de nuestra clase Informacion) y nuestro rbol debe seguir funcionando. Ya que se ha definido la clase que define la informacin que va a contener el rbol y como se compara esta informacin (en org.neos.arboles.binarios.estaticos.beans.Informacion) podemos comenzar a usar nuestro rbol. A continuacin se muestra un pequeo ejemplo:
package org.neos.arboles.binarios.estaticos; import java.util.ArrayList; import org.neos.arboles.binarios.estaticos.exceptions.ExceptionDesbordamientoVector; import org.neos.arboles.binarios.estaticos.exceptions.ExceptionDimensionInvalida; import org.neos.arboles.binarios.estaticos.exceptions.ExceptionElementoDuplicado; import org.neos.beans.Direccion; import org.neos.beans.Nombre; import org.neos.beans.Persona; public class Ejemplo {

public static void main(String[] args) throws ExceptionDimensionInvalida { ArbolBinarioEstatico arbol = new ArbolBinarioEstatico(27); ArrayList recorrido = null; int i, num_elems; Direccion direccion = null; Nombre nombre = null; Persona persona = null; try { direccion = new Direccion("AAA", 1, "B-1", "CCC", "DDD", "EEE"); nombre = new Nombre("Eugenio", "Flores", "Barrera"); persona = new Persona(nombre, direccion, null); arbol.insertarElemento(persona); nombre = new Nombre("Nayeli", "Vazquez", "Vasquez"); persona = new Persona(nombre, direccion, null); arbol.insertarElemento(persona); nombre = new Nombre("Hector", "Hidalgo", "Martinez"); persona = new Persona(nombre, direccion, null); arbol.insertarElemento(persona); nombre = new Nombre("Mario", "Hidalgo", "Matinez"); persona = new Persona(nombre, direccion, null); arbol.insertarElemento(persona); nombre = new Nombre("Miguel", "Flores", "Barrera"); persona = new Persona(nombre, direccion, null); arbol.insertarElemento(persona);

recorrido = arbol.recorridoPreorden(arbol.obtenerPosicionRaiz()); System.out.print("Recorrido Preorden: "); num_elems = recorrido.size(); for(i = 0; i < num_elems; i++) { System.out.print((Persona)recorrido.get(i) + " - "); } recorrido = arbol.recorridoInorden(arbol.obtenerPosicionRaiz()); System.out.print("\nRecorrido Inorden: "); num_elems = recorrido.size(); for(i = 0; i < num_elems; i++) { System.out.print((Persona)recorrido.get(i) + " - "); } recorrido = arbol.recorridoPostorden(arbol.obtenerPosicionRaiz()); System.out.print("\nRecorrido Postorden: "); num_elems = recorrido.size(); for(i = 0; i < num_elems; i++) { System.out.print((Persona)recorrido.get(i) + " - "); } System.err.println("\nNumero de elementos: "+arbol.obtenerNumeroElementos(arbol.obtenerPosicionRaiz())); System.err.println("Peso del rbol: "+arbol.obtenerPeso(arbol.obtenerPosicionRaiz())); System.err.println("Altura del rbol: "+arbol.obtenerAltura(arbol.obtenerPosicionRaiz())); } catch(ExceptionElementoDuplicado ed_e) { System.err.println(ed_e.getMessage()); } catch(ExceptionDesbordamientoVector dv_e) { System.err.println(dv_e.getMessage()); } } }

Con las instrucciones del inicio de nuestro pequeo ejemplo se crea un rbol como el mostrado en la siguiente figura:

Flores Barrera, Eugenio

Vazquez Vasquez, Nayeli

Hidalgo Martinez, Hugo

Flores Barrera, Miguel

Hidalgo Martinez, Mario

Figura 14. rbol construido con el ejemplo anterior Y para demostrar que lo que muestra la figura es cierto. Lo que debe desplegar nuestro pequeo ejemplo es lo siguiente:
Recorrido Preorden: Flores Barrera, Eugenio - Vazquez Vasquez, Nayeli - Hidalgo Martinez, Hector - Flores Barrera, Miguel - Hidalgo Matinez, Mario Recorrido Inorden: Flores Barrera, Eugenio - Flores Barrera, Miguel - Hidalgo Martinez, Hector - Hidalgo Matinez, Mario - Vazquez Vasquez, Nayeli Recorrido Postorden: Flores Barrera, Miguel - Hidalgo Matinez, Mario - Hidalgo Martinez, Hector - Vazquez Vasquez, Nayeli - Flores Barrera, Eugenio Numero de elementos: 5 Peso del rbol: 4 Altura del rbol: 3

Y con esto terminamos la implementacin de nuestro rbol dentro de un vector Ya solo resta que ustedes vean si les es til e implementarlo.

Implementacin dinmica de un rbol binario


Si aadimos a los rboles la restriccin de que cada elemento puede tener un solo posterior, llegamos a las estructuras lineales, y ms concretamente a las listas. As pues, las listas no son ms que un caso particular de los rboles. En este punto, si aadimos ciertas restricciones de acceso a las listas llegamos

a las colas o a las pilas. Por lo tanto, colas pilas, son tipos particulares de listas. As que se han implementado una lista dinmica lo que vamos a ver debe ser fcil. Y como vamos a reciclar el cdigo que generamos para el rbol dentro del vector ser ms parecido a una lista doblemente ligada. La estructura de nuestro nodo sigue siendo la misma que la de la Figura 7 y el mostrado en la siguiente figura:
NODO

Padre Informacin Izq Der

Figura 15. Nodo de un rbol binario con referencia hacia su padre Solo que en este caso las referencias hacia el padre, el hijo izquierdo y el hijo derecho son apuntadores hacia objetos (objetos nodo iguales al mostrado en la figura), de modo que al formar nuestro rbol dinmico se armara una estructura ms o menos parecida a la mostrada en la figura:

Padre Informacin Izq Der

Padre Informacin Izq Der

Padre Informacin Izq Der

Figura 16. Estructura del rbol dinmico Bueno, pues entonces vamos a ver la definicin en Java de la clase que representar nuestro rbol. En esta ocasin no voy a describir los mtodos ya que estamos reciclando el cdigo que se genero para el rbol en el vector, por lo tanto es muy parecido y creo que lo entendern para que sirve cada mtodo si lo relacionan con los mtodos del rbol visto anteriormente :-)

package org.neos.arboles.binarios.dinamicos; import java.util.ArrayList; import import import import org.neos.arboles.binarios.dinamicos.beans.Informacion; org.neos.arboles.binarios.dinamicos.beans.Nodo; org.neos.arboles.binarios.dinamicos.exceptions.ExceptionElementoDuplicado; org.neos.arboles.binarios.dinamicos.exceptions.ExceptionNoEncontrado;

public class ArbolBinario { private Nodo raiz; private ArrayList recorrido; public ArbolBinario() { this.raiz = null; this.recorrido }

= null;

public boolean esArbolVacio() { return (null == raiz) ? true : false; } public Nodo obtenerPosicionRaiz() { return raiz; } public boolean existeElemento(Object info) { Nodo nodo = obtenerElemento(info, raiz); if(null != nodo) { return true; } else { return false; } } public Nodo obtenerElemento(Object info, Nodo raiz) { if(null == raiz) { return raiz; } else { Informacion obj_info = new Informacion(info); Informacion obj_info_pa = new Informacion( raiz.getInformacion() );

if( obj_info_pa.equals(obj_info) ) { return raiz; } else if( obj_info.compareTo(obj_info_pa) < 0 ) { return obtenerElemento(info, raiz.getIzquierdo()); } else { return obtenerElemento(info, raiz.getDerecho()); } } }

public int obtenerNumeroElementos(Nodo nodo) { int num_elems = 0; if(null != nodo) { num_elems += obtenerNumeroElementos(nodo.getIzquierdo()); num_elems++; // contabilizar el nodo visitado num_elems += obtenerNumeroElementos(nodo.getDerecho()); } } return num_elems;

public int obtenerPeso(Nodo nodo) { int peso = 0; int num_h_izq = 0; int num_h_der = 0; if(null != nodo) { num_h_izq = obtenerNumeroElementos(nodo.getIzquierdo()); num_h_der = obtenerNumeroElementos(nodo.getDerecho()); } } public int obtenerAltura(Nodo nodo) { int altura = 0; Nodo ref_h_izq; Nodo ref_h_der; int altura_r_izq = 0; peso = num_h_izq + num_h_der;

return peso;

int altura_r_der = 0; if(null != nodo) { altura = 1; ref_h_izq = nodo.getIzquierdo(); ref_h_der = nodo.getDerecho(); if( (ref_h_izq != null) && (ref_h_der != null) ) { altura_r_izq = obtenerAltura(ref_h_izq); altura_r_der = obtenerAltura(ref_h_der); if(altura_r_izq >= altura_r_der) { altura += altura_r_izq; } else { altura += altura_r_der; } } else if( (ref_h_izq != null) && (ref_h_der == null) ) { altura += obtenerAltura(ref_h_izq); } else if( (ref_h_izq == null) && (ref_h_der != null) ) { altura += obtenerAltura(ref_h_der); } else if( (ref_h_izq == null) && (ref_h_der == null) ) { altura -= 1; }

} }

return altura; private boolean insertarElemento(Object info, Nodo nodo) { Nodo nuevo_nodo = null; Informacion obj_info = new Informacion(info); Informacion obj_info_pa = new Informacion( nodo.getInformacion() ); if( obj_info.compareTo(obj_info_pa) < 0 ) { if(nodo.getIzquierdo() == null) { nuevo_nodo = new Nodo(info); nuevo_nodo.setPadre(nodo); nodo.setIzquierdo(nuevo_nodo); return true; } else { return insertarElemento(info, nodo.getIzquierdo()); }

} else { if(nodo.getDerecho() == null) { nuevo_nodo = new Nodo(info); nuevo_nodo.setPadre(nodo); nodo.setDerecho(nuevo_nodo); return true; } else { return insertarElemento(info, nodo.getDerecho()); } } }

public boolean insertarElemento(Object info) throws ExceptionElementoDuplicado { boolean se_inserto = false; if( this.esArbolVacio() ) { this.raiz = new Nodo(info); se_inserto = true; } else { if( existeElemento(info) ) { throw new ExceptionElementoDuplicado("El elemento ya existe dentro del rbol!!"); } else { se_inserto = insertarElemento(info, raiz); } } } return se_inserto;

public boolean borrarElemento(Object info) throws ExceptionNoEncontrado { Nodo nodo = null; boolean se_borro = false; if( this.esArbolVacio() ) { throw new ExceptionNoEncontrado("El rbol esta vaco!!"); } else { if( existeElemento(info) ) { nodo = obtenerElemento(info, raiz); if(nodo.getPadre() != null) { if( (nodo.getIzquierdo() != null) || (nodo.getDerecho() != null) ) {

se_borro = borrarNodoInterior(nodo); } else { se_borro = borrarNodoHoja(nodo); } } else { se_borro = borrarNodoRaiz(nodo); } } else { throw new ExceptionNoEncontrado("El elemento no existe dentro del rbol!!"); } } } return se_borro;

private boolean borrarNodoInterior(Nodo nodo) { boolean respuesta = false; Nodo nodo_padre = nodo.getPadre(); Nodo nodo_izq = nodo.getIzquierdo(); Nodo nodo_der = nodo.getDerecho(); Nodo nodo_c = null; if( (nodo.getIzquierdo() != null) && (nodo.getDerecho() != null) ) { if(nodo_padre.getIzquierdo() == nodo) { nodo_padre.setIzquierdo(nodo_der); } else { nodo_padre.setDerecho(nodo_der); } nodo_der.setPadre(nodo_padre); nodo_c = new Nodo(nodo_izq.getInformacion()); nodo_c.setDerecho(nodo_izq.getDerecho()); nodo_c.setIzquierdo(nodo_izq.getIzquierdo()); nodo = null; nodo_izq = null; insertarElemento(nodo_c.getInformacion(), nodo_der); respuesta = true; } else if(nodo.getIzquierdo() != null) { nodo_izq.setPadre(nodo_padre); if(nodo_padre.getDerecho() == nodo) {

nodo_padre.setDerecho(nodo_izq); } else { nodo_padre.setIzquierdo(nodo_izq); } nodo = null; respuesta = true; } else { nodo_der.setPadre(nodo_padre); if(nodo_padre.getDerecho() == nodo) { nodo_padre.setDerecho(nodo_der); } else { nodo_padre.setIzquierdo(nodo_der); } nodo = null; respuesta = true; } return respuesta; } private boolean borrarNodoHoja(Nodo nodo) { boolean se_borro = false; Nodo nodo_padre = nodo.getPadre(); if(nodo_padre.getDerecho() == nodo) { nodo_padre.setDerecho(null); } else { nodo_padre.setIzquierdo(null); } nodo = null; se_borro = true; } return se_borro;

private boolean borrarNodoRaiz(Nodo nodo) { boolean se_borro = false; Nodo nodo_izq = nodo.getIzquierdo(); Nodo nodo_der = nodo.getDerecho(); Nodo nodo_c = null; if( (nodo.getIzquierdo() != null) && (nodo.getDerecho() != null) ) { this.raiz = nodo_der;

this.raiz.setPadre(null); nodo_c = new Nodo(nodo_izq.getInformacion()); nodo_c.setDerecho(nodo_izq.getDerecho()); nodo_c.setIzquierdo(nodo_izq.getIzquierdo()); nodo = null; nodo_izq = null; insertarElemento(nodo_c, raiz); se_borro = true; } else if(nodo.getIzquierdo() != null) { this.raiz = nodo_izq; this.raiz.setPadre(null); nodo = null; se_borro = true; } else if(nodo.getDerecho() != null) { this.raiz = nodo_der; this.raiz.setPadre(null); nodo = null; se_borro = true; } else { this.raiz = null; se_borro = true; } return se_borro;

public ArrayList recorridoPreorden(Nodo nodo) { if(nodo == raiz) { recorrido = new ArrayList(); } if(null != nodo) { recorrido.add(nodo.getInformacion()); recorridoPreorden(nodo.getIzquierdo()); recorridoPreorden(nodo.getDerecho()); } return recorrido; } public ArrayList recorridoInorden(Nodo nodo) {

if(nodo == raiz) { recorrido = new ArrayList(); } if(null != nodo) { recorridoInorden(nodo.getIzquierdo()); recorrido.add(nodo.getInformacion()); recorridoInorden(nodo.getDerecho()); } return recorrido; } public ArrayList recorridoPostorden(Nodo nodo) { if(nodo == raiz) { recorrido = new ArrayList(); } if(null != nodo) { recorridoPostorden(nodo.getIzquierdo()); recorridoPostorden(nodo.getDerecho()); recorrido.add(nodo.getInformacion()); } return recorrido;

} }

Y bueno, pues el ya tan tradicional pequeo ejemplo que utiliza nuestro rbol, para demostrar que este funciona, o que por lo menos lo funciona lo esencial. El cdigo de nuestro ejemplo es el cdigo del ltimo ejemplo del rbol contenido en el vector, solo que utilizando nuestro rbol dinmico, por lo que utiliza las mismas clases que se usaron en el ejemplo anterior para almacenar la informacin.
package org.neos.arboles.binarios.dinamicos; import java.util.ArrayList; import import import import org.neos.arboles.binarios.dinamicos.exceptions.ExceptionElementoDuplicado; org.neos.beans.Direccion; org.neos.beans.Nombre; org.neos.beans.Persona;

public class Ejemplo {

public static void main(String[] args) { ArbolBinario arbol = new ArbolBinario(); ArrayList recorrido = null; int i, num_elems; Direccion direccion = null; Nombre nombre = null; Persona persona = null; try { direccion = new Direccion("AAA", 1, "B-1", "CCC", "DDD", "EEE"); nombre = new Nombre("Eugenio", "Flores", "Barrera"); persona = new Persona(nombre, direccion, null); arbol.insertarElemento(persona); nombre = new Nombre("Nayeli", "Vazquez", "Vasquez"); persona = new Persona(nombre, direccion, null); arbol.insertarElemento(persona); nombre = new Nombre("Hector", "Hidalgo", "Martinez"); persona = new Persona(nombre, direccion, null); arbol.insertarElemento(persona); nombre = new Nombre("Mario", "Hidalgo", "Matinez"); persona = new Persona(nombre, direccion, null); arbol.insertarElemento(persona); nombre = new Nombre("Miguel", "Flores", "Barrera"); persona = new Persona(nombre, direccion, null); arbol.insertarElemento(persona); recorrido = arbol.recorridoPreorden(arbol.obtenerPosicionRaiz()); num_elems = recorrido.size(); for(i = 0; i < num_elems; i++) { System.out.print((Persona)recorrido.get(i) + " - "); } recorrido = arbol.recorridoInorden(arbol.obtenerPosicionRaiz()); System.out.print("\nRecorrido Inorden: "); num_elems = recorrido.size(); for(i = 0; i < num_elems; i++) { System.out.print((Persona)recorrido.get(i) + " - "); } recorrido = arbol.recorridoPostorden(arbol.obtenerPosicionRaiz()); System.out.print("\nRecorrido Postorden: "); num_elems = recorrido.size(); for(i = 0; i < num_elems; i++) { System.out.print((Persona)recorrido.get(i) + " - ");

} System.err.println("\nNumero de elementos: "+arbol.obtenerNumeroElementos(arbol.obtenerPosicionRaiz())); System.err.println("Peso del rbol: "+arbol.obtenerPeso(arbol.obtenerPosicionRaiz())); System.err.println("Altura del rbol: "+arbol.obtenerAltura(arbol.obtenerPosicionRaiz())); } catch(ExceptionElementoDuplicado ed_e) { System.err.println(ed_e.getMessage()); } } }

Con nuestro pequeo ejemplo se crea un rbol como el mostrado en la Figura 14. Y para demostrar que lo que muestra la figura es cierto. Lo que debe desplegar nuestro pequeo ejemplo es lo siguiente:
Recorrido Preorden: Flores Barrera, Eugenio - Vazquez Vasquez, Nayeli - Hidalgo Martinez, Hector - Flores Barrera, Miguel - Hidalgo Matinez, Mario Recorrido Inorden: Flores Barrera, Eugenio - Flores Barrera, Miguel - Hidalgo Martinez, Hector - Hidalgo Matinez, Mario - Vazquez Vasquez, Nayeli Recorrido Postorden: Flores Barrera, Miguel - Hidalgo Matinez, Mario - Hidalgo Martinez, Hector - Vazquez Vasquez, Nayeli - Flores Barrera, Eugenio Numero de elementos: 5 Peso del rbol: 4 Altura del rbol: 3

Algo que podramos hacer para mejorar nuestro rbol sera implementar un mtodo que permita balancear nuestro rbol para que no tengamos una rama ms larga que otra y de esta forma tratar de optimizar bsquedas e inserciones. Algo que se me ocurre para implementar este mtodo es vaciar todos los elementos del rbol a un vector (en el vector los elementos estaran ordenados de menor a mayor) y despus volver a reconstruir todo el rbol tomando como raz el elemento que se encuentra a la mitad del vector; al tomar el elemento del centro nuestro vector se dividira en dos partes (una izquierda, con los elementos ms pequeos; y una derecha, con los elementos ms grandes) por lo tanto debemos hacer lo mismo para la parte izquierda y la parte derecha (tomar el elemento del centro como raz) de manera recursiva hasta terminar con ambas partes del vector. Otra opcin, aun mejor, sera implementar los algoritmos para rboles equilibrados (AVL). Otra muy buena mejora a nuestro rbol sera hacerlo independiente de la informacin que almacena y que siguiera teniendo la informacin ordenada, para eliminar las modificaciones que tenemos que hacer a la clase Informacion cada ves que queremos que el rbol almacene otro tipo de informacin.

You might also like