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

estructura estática (un vector) o dinámicamente (semejante a una lista ligada). Descripción: A lo largo de la siguiente práctica se mostrarán algunos conceptos útiles para comprender que es y para que pudiera servir un árbol, además de que se mostrarán dos pequeños ejemplos que muestran algunos ejemplos de utilidad para árboles binarios. Nota:
El presente documento es una pequeña síntesis sobre árboles binarios. Se trata este tema porque estos representan una de las estructuras de datos más importantes en computación y estos pueden aplicarse para la solución de una gran variedad de problemas, pero no muchas personas los ven como una buena solución 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 comprensión. Y así después cada uno de nosotros podamos definir si es conveniente aplicarlos a la solución de algún problema o si alguna otra estructura de datos puede ser una mejor opción. Puesto que solo veremos árboles las estructuras de datos alternativas corren por su cuenta :-)

Desarrollo:

Conceptos y Terminología básica
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 homogénea en el que cada elemento puede tener varios elementos posteriores, pero tan sólo puede tener un elemento anterior. - Es una estructura jerárquica aplicada sobre una colección de elementos u objetos llamados nodos; de los cuales uno es conocido como raíz. Además se crea una relación o parentesco entre los nodos dando lugar a términos 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 raíz de un árbol completo. - Son estructuras dinámicas no lineales. Dinámicas porque las estructuras de árbol pueden cambiar durante la ejecución 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 más general son los grafos. En un grafo cada elemento puede tener varios elementos anteriores y varios elementos posteriores. Los árboles no son más que un tipo especial de grafo en el que cada elemento puede tener varios elementos posteriores, pero tan sólo puede tener un elemento anterior. Tanto grafos como árboles son estructuras no lineales. Creo que la mayoría, sino es que todos, hemos utilizado los árboles cuando hemos hecho un árbol genealógico o alguna estructura jerárquica de alguna organización. Y que me dicen de la forma en la que organizamos la información en nuestras maquinas (se hace en una estructura de directorios y subdirectorios en forma de árbol, para facilitar su búsqueda). Talvez sin darnos cuenta, pero hemos manejado el concepto de árbol .

Además de la definición debemos conocer otros conceptos bastante importantes, pues estos pudieran ser útiles a la hora de codificar un árbol: En relación 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. También 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. También se dice que X es descendiente directo de Y. En la Figura 1: E es hijo de B.  Hermano. Dos nodos serán hermanos si son descendientes directos de un mismo nodo. En la Figura 1: E y F son hermanos. En cuanto a la posición dentro del árbol:  Nodo raíz. 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 raíz.  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 raíz ni hoja. En la Figura 1 D es un nodo interior. Existen otros conceptos que definen las características del árbol, en relación a su tamaño:  Orden. Es el número 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. Podríamos decir que nuestro árbol de ejemplo (Figura 1) es de orden tres.  Grado. El número de hijos que tiene el elemento con más 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 más de tres hijos.  Nivel. Se define para cada elemento del árbol como la distancia a la raíz, medida en nodos. El nivel de la raíz 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 raíz de un árbol, también podemos hablar de altura de ramas; el máximo número de nodos que hay que recorrer para llegar de la raíz 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 número de nodos del árbol sin contar la raíz.  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 número de arcos que deben ser recorridos para llegar desde la raíz al nodo X. Por definición la raíz 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 raíz a una hoja. En el ejemplo A-B-E-K y A-B-F son ramas.

A

B

C

D

E

F

G

H

I

J

K

L

M

N

O

Figura 1. Árbol de grado tres Los árboles tienen una gran variedad de aplicaciones. Por ejemplo, se pueden utilizar para representar fórmulas matemáticas, para organizar adecuadamente la información, para construir un árbol genealógico, para el análisis de circuitos eléctricos, para numerar los capítulos y secciones de un libro, etc. Bueno y como dijimos que lo que se vería 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 también como árboles binarios, ya que cada nodo del árbol no tendrá más 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 vacío, ó b. Esta formado por un nodo cuyos subárboles izquierdo y derecho son a su vez árboles binarios.
N

E

R

A

G

O

V

U

Figura 2. Ejemplo de un árbol binario En alguna de las definiciones del inicio del documento, la tercera para ser precisos, se utiliza la recursión para definir un árbol porque representa la forma más apropiada y porque además es una característica inherente de los mismos. En cualquier árbol, no sólo en los binarios, si eliminamos el nodo raíz, obtenemos dos árboles; en el caso de que sea un árbol binario. Aquel que colgaba del enlace izquierdo del nodo raíz se denomina subárbol izquierdo y aquel que colgaba del enlace derecho se denomina subárbol derecho. Además, en un árbol binario, todos los subárboles son también árboles binarios. De hecho, a partir de cualquier nodo de un árbol podemos definir un nuevo árbol sin más que considerarlo como su nodo raíz. Por tanto, cada nodo tiene asociados un subárbol derecho y uno izquierdo. Existen dos tipos de árboles binarios que se consideran especiales en función 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(subárbol_izquierdo) – altura(subárbol_derecho) | ≤ 1
M

E

R

N

A

O

V

E

N

Q

A

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 están en el mismo nivel. Se denomina completo porque cada nodo, excepto las hojas, tiene el máximo de hijos que puede tener.

y las tres se suelen implementar mediante recursividad. Se trata de aquellos recorridos que incluyen todo el árbol. Árbol binario completo Recorridos por árboles Una de las cosas que debemos poder hacer con un árbol es poder movernos a través de la información que este contiene. El orden es Nodo – Izquierda – Derecha (N – I – D). El modo evidente de moverse a través de las ramas de un árbol es siguiendo las referencias de los nodos que las componen. después el nodo y finalmente la ultima rama (rama derecha).N E R A G O V Figura 5. aunque sea muy necesaria . posteriormente se recorre la rama izquierda y finalmente la rama derecha. 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.Pre-orden . Implementaciones del Árbol binario .Post-orden Recorrido Pre-orden (N – I – D) En este recorrido lo primero que se obtiene o evalúa es el nodo. pero hay ciertos recorridos que usaremos frecuentemente. 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). Estos tres casos son: . Hay tres formas de recorrer un árbol completo.In-orden . El orden de este recorrido es: Izquierda – Derecha – Nodo (I – D – N). antes de recorrer las ramas. Los recorridos dependen en gran medida del tipo y propósito del árbol. En los tres casos se sigue siempre a partir de cada nodo todas las ramas una por una. 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 mayoría de nosotros no nos agrada mucho la teoría. pues vamos viendo algo práctico. El orden es: Izquierda – Nodo – Derecha (I – N – D).

registros y conjuntos. Cada nodo del árbol estará formado por tres partes: • La información contenida en el nodo.Para poder implementar un árbol binario primero debemos definir la estructura de los nodos. la cual puede ser un tipo primitivo o puede ser cualquier tipo de objeto • Un enlace al hijo derecho (raíz del subárbol derecho) • Un enlace al hijo izquierdo (raíz del subárbol izquierdo) Gráficamente: NODO Información Izq Der Figura 6. la cual puede ser un tipo primitivo o puede ser cualquier tipo de objeto • Un enlace al hijo derecho (raíz del subárbol derecho) • Un enlace al hijo izquierdo (raíz del subárbol izquierdo) Gráficamente: NODO Padre Información Izq Der Figura 7. Las estáticas son arreglos. y no sólo hacia las hojas. Nodo de un árbol binario Frecuentemente. para hacer más fácil moverse a través del árbol. aunque tampoco es estrictamente necesario. añadiremos un puntero a cada nodo que apunte al nodo padre. Si implementamos este puntero nuestro nodo estaría compuesto por cuatro partes: • Un enlace al padre del nodo • La información contenida en el nodo. Implementación estática de un árbol binario mediante un vector . De este modo podremos avanzar en dirección a la raíz. mientras que las dinámicas están representadas por listas. Nodo de un árbol binario con referencia hacia su padre Los árboles pueden ser construidos con estructuras estáticas y dinámicas.

padre. el hijo izquierdo y el hijo derecho. this. utilizaremos números enteros que serán los índices en el vector donde se encuentran: el padre. izquierdo.izquierdo = -1.izquierdo = -1.bean::Nodo -informacion : Object -padre : int -derecho : int -izquierdo : int Figura 8. } public void setIzquierdo(int izquierdo) { .neos. derecho. } public int getInformacion() { return informacion.informacion = -1.Para realizar la implementación estática del árbol binario utilizamos una estrategia en la que simulamos la memoria dinámica mediante el uso de un vector.derecho = -1. Una representación de nuestra clase Nodo sería la siguiente: org.neos. public Nodo() { this.estaticos. en la Figura 7. en lugar de apuntadores. Cada registro contendrá un nodo con los cuatro campos especificados anteriormente. this. this. this.binarios. y todos los nodos se almacenan en un vector. } public void setDerecho(int derecho) { this.binarios. } public int getIzquierdo() { return izquierdo. } public Nodo(int informacion) { this.derecho = derecho.estaticos.derecho = -1. } public int getDerecho() { return derecho. public class Nodo private int private int private int private int { informacion.informacion = informacion.arboles.arboles.beans. Para implementar los enlaces. Clase Nodo Y su definición en Java sería la siguiente: package org.

getInformacion(). } public boolean equals(Object nodo) { Nodo _nodo = (Nodo)nodo. De modo que quedaría de la siguiente forma. Así no tenemos que modificar el código del árbol si queremos que este almacene otro tipo de información… Aunque tendíamos que redefinir nuestro Wrapper  Bueno pues pasemos a ver nuestro Wrapper para la información que almacenará nuestro árbol.estaticos. El árbol que implementaremos permitirá las siguientes operaciones: .equals(info_nodo). org. Ya tenemos la clase con la cual podemos crear instancias de nuestros nodos. } } Como vemos nuestro nodo es una clase muy simple la cual tiene cuatro variables de instancia y los métodos get y set de estas.insertar elementos . puesto que esta puede ser de cualquier tipo. este método es: “equals(Object)”. Perdón.izquierdo = izquierdo. public void setInformacion(int informacion) { this. Object info_nodo = _nodo. Para este ejemplo solo vamos a almacenar cadenas (pero solo para poder representar árboles como los que vimos en los ejemplos de la teoría).neos. return this. así que ahora vamos a implementar la clase que representará a nuestro árbol… Ahh pero antes de eso… Además utilizaremos una especie de Wrapper para la información que contendrá cada nodo del árbol. inorden y postorden) . para poder trabajar con otro tipo de información lo único que debemos cambiar es el tipo de la propiedad “contenido” y hacer que compareTo se haga la comparación de forma correcta y en el constructor y el set de la información se haga el cast al tipo correcto.arboles. Adicional a los métodos get y set contiene un método que nos será útil para saber si nuestro nodo es igual a otro nodo. pero fue la única forma que se me ocurrió para hacer independiente la información de la estructura del árbol.informacion.} this. el cual estamos sobrescribiendo del método que proporciona Object. con respecto al tipo de la variable “contenido”.recorrer el árbol (preorden. Wrapper para la información que almacenará el árbol Teóricamente. ya lo único que no sabe el árbol es como comparar la información que contendrán sus nodos. Pero los nodos no contendrán objetos del Wrapper este solo nos será útil para cuando hagamos comparaciones entre la información de los nodos.borrar elementos .binarios.informacion = informacion.bean::Informacion -contenido : String +equals(in info : Object) : Boolean +compareTo info : Object) : int (in Figura 9.

El campo que es importante conservar siempre es el nodo raíz. in posicion _nodo : int) : Boolean ( -borrarNodoRaiz nodo : ArbolBinarioEstatico. in posicion _actual : int) : Boolean +insertarElemento(in info : String) : Boolean -borrarNodoHoja nodo : ArbolBinarioEstatico. 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. el hijo izquierdo de un nodo debe ser menor y el hijo derecho debe ser mayor al hijo izquierdo y al nodo.neos. De modo que la clase que representa nuestro árbol quedará de la siguiente forma: org.- Obtener el peso del árbol o una rama (mediante la posición del nodo. donde algunos de estos son privados y otros públicos. en el vector) Obtener el número de nodos del árbol o una rama (mediante la posición del nodo. 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.binarios. En nuestro caso tendremos dos variables más dentro de nuestro árbol: el vector en el que se almacenarán los nodos de nuestro árbol y una arreglo (ArrayList) en el que almacenaremos los recorridos del árbol. es decir.estaticos::ArbolBinarioEstatico -arbol : Nodo[] -posicion_raiz : int -recorrido : ArrayList +ArbolBinarioEstatico(in num_elementos : int) : Nodo +esArbolVacio() : Boolean +obtenerPosicionRaiz() : int -obtenerPosicionElemento(in info : String. Clase para el árbol contenido en un vector Como podemos darnos cuenta nuestro árbol tiene varios métodos. 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.arboles. in posicion_actual : int) : Boolean -insertarElemento(in info : String. A continuación veremos una descripción de estos métodos: . in posicion _nodo : int) : Boolean (in -borrarNodoInterior in nodo : ArbolBinarioEstatico. en el vector) Obtener la altura de árbol o una rama (mediante la posición del nodo. en el vector) Además será un árbol ordenado.

Return: . public int obtenerPosicionRaiz() Obtener la posición del nodo raíz. Return: Posición del elemento que representa al nodo raíz.Información: a buscar dentro del árbol.false cuando el árbol contiene elementos. .true cuando el árbol no contiene elementos. public boolean existeElemento(Object info) Obtener respuesta a la pregunta ¿Existe el elemento en el árbol? Parámetros: . Parámetros: . .ArrayIndexOutOfBoundsException: Si la posición del elemento a buscar es -1. Se obtiene -1 (NULL) si el árbol esta vacío. El nodo al que se apunta (ya sea izquierdo o derecho) antes de llamar a esta función es nulo (NULL). public boolean esArbolVacio() Método útil para preguntar es nuestro árbol esta vacío o no. . public int obtenerPosicionElemento(Object info) throws ArrayIndexOutOfBoundsException Buscar un elemento en base a la información que contienen los elementos del árbol.Métodos públicos public ArbolBinarioEstatico(int num_elementos) throws ExceptionDimensionInvalida Constructor que permite crear un árbol contenido en un vector de un tamaño definido. Parámetros: . Return: Posición del elemento del vector que contiene la información indicada. Throws: .true cuando un elemento en el árbol contiene la información especificada.info: Información que contiene el elemento que se esta buscando.num_elementos: Número de elementos que podrá contener el vector. Return: . dentro del vector.false cuando ningún elemento en el árbol contiene la información especificada.ExceptionDimensionInvalida: En caso de que el tamaño del vector no sea valido. Throws: .

public int obtenerPeso(int raiz) Obtener el peso del árbol o una rama especificada. del nodo que se toma como raíz.raiz: Posición del elemento que es la raíz del árbol o subárbol. Return Número de elementos que puede almacenar el árbol. Return: Peso del árbol o rama especificada. Parámetros: .public Nodo obtenerElemento(Object info) Obtener el elemento (Nodo) que contiene la información indicada. .null. dentro del vector. cuando la información especificada no existe dentro del árbol. public int obtenerNumeroElementos(int posicion) Obtener el número de elementos que contiene una rama especificada. La altura de un árbol se define como el nivel del nodo de mayor nivel Parámetros: .raiz: Posición. Return: .elemento que contiene la infoemación.posicion: Posición del elemento para el que se cuenta el número de nodos que cuelgan de él. public int obtenerAltura(int raiz) Obtener la altura de un árbol o rama de un árbol binario. cuando la información existe dentro del árbol. Parámetros: . Return: Número de nodos que cuelgan del nodo indicado. Return: Altura del árbol o rama. public boolean insertarElemento(Object info) throws ExceptionDesbordamientoVector. ExceptionElementoDuplicado .info: Información que se busca dentro del árbol. public int obtenerCapacidadArbol() Obtener el número de elementos que puede almacenar el árbol. Parámetros: . Que sería algo así como contar el número de nodos que cuelgan a la izquierda y derecha del nodo.

Parámetros: .ExceptionNoEncontrado: Si el elemento especificado no existe dentro del árbol.ExceptionDesbordamientoVector: Si el vector que representa el árbol ya esta lleno. . Parámetros: . si es que este puede ser insertado. Return: Arreglo que contiene el recorrido del árbol.info: Información que contendrá el nuevo elemento. Return: Respues ta a la pregunta ¿Se borro el elemento? Throws: . .info: Elemento que quiere eliminarse. Nodo. Izquierda.posicion: Posición a partir de la cual se comienza el recorrido. public String recorridoPreorden(int posicion) Recorrido (Nodo. public String recorridoInorden(int posicion) Recorrido (Izquierda. Nodo) Parámetros: . public String recorridoPostorden(int posicion) Recorrido (Izquierda.Comprobar si se puede crear e insertar un nuevo elemento con la información indicada. Return: La respuesta a la pregunta ¿Se inserto el elemento? Throws: . public boolean borrarElemento(Object info) throws ExceptionNoEncontrado Borrar un elemento del árbol. Derecha. Return: Arreglo que contiene el recorrido del árbol. Derecha) Parámetros: .ExceptionElementoDuplicado: Si la información que se quiere insertar ya existe dentro del árbl. Derecha) Parámetros: .posicion: Posición apartir de la cual se comienza el recorrido.posicion: Posición apartir de la cual se comienza el recorrido.

Throws: . . Parámetros: . El nodo al que se apunta (ya sea izquierdo o derecho) antes de llamar a esta función es nulo (NULL). private int obtenerPosicionLibre() Buscar dentro del vector que representa el árbol una casilla que este libre o vacía.info: Información que contendrá el nuevo nodo.info: Información que contiene el elemento que se esta buscando. Return: La respuesta a la pregunta ¿Se inserto el elemento? private boolean insertarElemento(Nodo nuevo_nodo. . Return: La respuesta a la pregunta ¿Se inserto el elemento? . Métodos privados private int obtenerPosicionElemento(Object info.ArrayIndexOutOfBoundsException: Si la posición del elemento a buscar es -1. Este método se encarga de agregar el elemento dentro del vector que representa el árbol.nuevo_nodo: Infrmación que contendrá el nuevo nodo. con el que se compara la información. Parámetros: . private boolean insertarElemento(Object info.posicion_actual: Posición del nodo contra el que se compara la información. .Return: Arreglo que contiene el recorrido del árbol. Return: Posición del elemento del vector que contiene la información indicada. Este método se encarga de agregar el elemento dentro del vector que representa el árbol. int posicion_actual) Método de apoyo a InsertarElemento(int). int posicion_actual) Método de apoyo a InsertarElemento(int).posicion_actual: Posición del nodo contra el que se compara la información. Parámetros: . int posicion_actual) throws ArrayIndexOutOfBoundsException Buscar un elemento recorriendo los elementos del árbol. Return: Posición del vector que no contiene un nodo.posicion_actual: Posición del elemento actual.

estaticos. int posicion_nodo) Borrar un nodo que es una hoja.estaticos.estaticos. .neos.neos. Return: Respuesta a la pregunta ¿Se borro el nodo? private boolean borrarNodoRaiz(Nodo nodo.binarios. org.nodo: Nodo a borrar. int posicion_nodo) Borrar el nodo que es la raíz del árbol.arboles.ArrayList.arboles.ExceptionDesbordamientoVector. tiene por lo menos una rama y no es el noso raíz del árbol. Return: Respuesta a la pregunta ¿Se borro el nodo? private boolean borrarNodoHoja(Nodo nodo.beans. .exceptions. Parámetros: . int posicion_nodo) Borrar un nodo interior.ConstantesArbolBinarioEstatico. import import import import import import org.binarios.binarios.estaticos.constantes.ExceptionDimensionInvalida.arboles.estaticos.exceptions. org.arboles. Parámetros: . Return: Respuesta a la pregunta ¿Se borro el nodo? Definición de la clase que representa el árbol: package org.neos.posicion_nodo: Posición del nodo dentro del vector.private boolean borrarNodoInterior(Nodo nodo. . org.nodo: Nodo a borrar.neos.nodo: Nodo que se quiere borrar. en el vector.neos. org.neos.exceptions.arboles.beans.Nodo.ExceptionElementoDuplicado.posicion_nodo: Posición del nodo a borrar. import java. en el vector.estaticos.binarios.binarios. org.estaticos.arboles.util. del nodo a borrar. .posicion_nodo: Posición.binarios.binarios.arboles. Parámetros: .neos.Informacion.

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

getInformacion() ).getDerecho()).compareTo(obj_info) > 0 ) { return obtenerPosicionElemento(info. } else { return obtenerPosicionElemento(info. } public Nodo obtenerElemento(Object info) { int posicion_elemento = -1. try { posicion_elemento = obtenerPosicionElemento(info). nodo_raiz. } } return elemento. } return respuesta. elemento = arbol[posicion_elemento]. int posicion_elemento = -1. } catch(ArrayIndexOutOfBoundsException aioob_e) { respuesta = false. if(NULL != posicion) { . } catch(ArrayIndexOutOfBoundsException aioob_e) { .equals(obj_info) ) { return posicion_raiz. public int obtenerNumeroElementos(int posicion) { int num_elems = 0. if( obj_info_r.getIzquierdo()). } } public boolean existeElemento(Object info) { boolean respuesta = false. Informacion obj_info_r = new Informacion( nodo_raiz. respuesta = true. } else if( obj_info_r. try { posicion_elemento = obtenerPosicionElemento(info). Nodo elemento = null.Informacion obj_info = new Informacion(info). nodo_raiz.

if(NULL != raiz) { altura = 1. ref_h_izq = nodo. int ref_h_izq.Nodo nodo = arbol[posicion]. peso = num_h_izq + num_h_der. ref_h_der = nodo. int altura_r_izq = 0. if(NULL != raiz) { nodo = arbol[raiz]. int num_h_der = 0.getDerecho()). int ref_h_der.getDerecho()). public int obtenerPeso(int raiz) { int peso = 0. Nodo nodo = null. num_h_der = obtenerNumeroElementos(nodo. } } return peso. int num_h_izq = 0. nodo = arbol[raiz]. } } return (num_elems). int altura_r_der = 0. Nodo nodo = null. num_elems += obtenerNumeroElementos(nodo. num_elems++.getIzquierdo()).getIzquierdo().getIzquierdo()). num_elems += obtenerNumeroElementos(nodo. num_h_izq = obtenerNumeroElementos(nodo. public int obtenerAltura(int raiz) { int altura = 0.getDerecho(). if( (ref_h_izq != NULL) && (ref_h_der != NULL) ) { .

altura_r_der = obtenerAltura(ref_h_der). for(i = 0. } } return NULL. } } } return altura. } private boolean insertarElemento(Object info. int posicion = NULL. public int obtenerCapacidadArbol() { return arbol. if(altura_r_izq >= altura_r_der) { altura += altura_r_izq. Informacion obj_info_pa = new Informacion( nodo. Nodo nuevo_nodo = null.altura_r_izq = obtenerAltura(ref_h_izq). longitud = arbol. } else if( (ref_h_izq == NULL) && (ref_h_der != NULL) ) { altura += obtenerAltura(ref_h_der).length.getIzquierdo() == NULL) { .compareTo(obj_info) > 0 ) { if(nodo. Informacion obj_info = new Informacion(info). i++) { if(null == arbol[i]) { return i. } } else if( (ref_h_izq != NULL) && (ref_h_der == NULL) ) { altura += obtenerAltura(ref_h_izq). int posicion_actual) { Nodo nodo = arbol[posicion_actual]. } else if( (ref_h_izq == NULL) && (ref_h_der == NULL) ) { altura -= 1.getInformacion() ). i < longitud. if( obj_info_pa. } else { altura += altura_r_der.length. } private int obtenerPosicionLibre() { int i.

return true. boolean se_inserto = false. if( this. nodo. } else { return insertarElemento(info. nodo. nodo. nodo. nuevo_nodo = new Nodo(info).posicion = obtenerPosicionLibre(). arbol[posicion] = nuevo_nodo. } } else { if(nodo. arbol[0] = nuevo_nodo. . nuevo_nodo.getDerecho()). se_inserto = true. ExceptionElementoDuplicado { Nodo nuevo_nodo = null. nuevo_nodo.setPadre(posicion_actual). } else { return insertarElemento(info. } } } public boolean insertarElemento(Object info) throws ExceptionDesbordamientoVector. return true. } else { if(obtenerNumeroElementos(posicion_raiz) == arbol.getIzquierdo()).setIzquierdo(posicion).setDerecho(posicion). no pueden agregarse más elementos!!").length) { throw new ExceptionDesbordamientoVector("El árbol esta lleno.getDerecho() == NULL) { posicion = obtenerPosicionLibre(). arbol[posicion] = nuevo_nodo.posicion_raiz = 0.esArbolVacio() ) { nuevo_nodo = new Nodo(info).setPadre(posicion_actual). this. nuevo_nodo = new Nodo(info).

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

nodo.getIzquierdo() != NULL) && (nodo. int posicion_nodo) { boolean respuesta = false. } else { return insertarElemento(nuevo_nodo. Nodo nodo_padre = null. Informacion obj_info_pa = new Informacion( nodo. Nodo nodo_aux = null. Informacion obj_info = new Informacion( nuevo_nodo. if( (nodo.setPadre(posicion_actual).getDerecho()).} private boolean insertarElemento(Nodo nuevo_nodo.setIzquierdo(posicion). nodo. nuevo_nodo. int posicion_actual) { Nodo nodo = arbol[posicion_actual]. int posicion = NULL. int posicion_ins = NULL. } } else { if(nodo. int posicion_aux = NULL. return true.getInformacion() ). arbol[posicion] = nuevo_nodo. nodo.getDerecho() != NULL) ) { . } else { return insertarElemento(nuevo_nodo. nuevo_nodo. arbol[posicion] = nuevo_nodo. return true. if( obj_info_pa.getInformacion() ).compareTo(obj_info) > 0 ) { if(nodo. } } } private boolean borrarNodoInterior(Nodo nodo. nodo.setPadre(posicion_actual).getIzquierdo()).setDerecho(posicion).getDerecho() == NULL) { posicion = obtenerPosicionLibre().getIzquierdo() == NULL) { posicion = obtenerPosicionLibre().

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

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

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

binarios.getDerecho()).ExceptionElementoDuplicado. recorridoPostorden(nodo.insertarElemento("G").estaticos.exceptions.util.insertarElemento("D"). } return recorrido.binarios. ArrayList recorrido = null. .ExceptionNoEncontrado.exceptions.insertarElemento("N").arboles. arbol. } if(NULL != posicion) { Nodo nodo = arbol[posicion]. } } Y un pequeño ejemplo en el que se muestra las funciones más importantes de nuestro árbol: package org.neos.binarios.ArrayList. try { arbol. org.estaticos.neos. arbol. public ArrayList recorridoPostorden(int posicion) { if(posicion == posicion_raiz) { recorrido = new ArrayList(). int i.insertarElemento("J").binarios.estaticos.estaticos. public class Ejemplo { public static void main(String[] args) throws ExceptionDimensionInvalida { ArbolBinarioEstatico arbol = new ArbolBinarioEstatico(27). recorrido.binarios.exceptions. org. import import import import org.estaticos.ExceptionDesbordamientoVector.neos.neos.getIzquierdo()).add(nodo. arbol. num_elems. org.arboles. arbol.getInformacion()).insertarElemento("E").ExceptionDimensionInvalida.arboles. import java.arboles.} return recorrido.arboles. recorridoPostorden(nodo.exceptions.neos.

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

out.obtenerPosicionRaiz()).println(dv_e.getMessage()). num_elems = recorrido.println("Altura del árbol: "+arbol.obtenerPosicionRaiz())).get(i) + " .println("Peso del árbol: "+arbol.println(ed_e.obtenerPeso(arbol.out.obtenerNumeroElementos(arbol. } System. } catch(ExceptionNoEncontrado ne_e) { System. System.err. i++) { System.").err. i < num_elems.err. Árbol construido con el programa ejemplo. System.err.recorridoPostorden(arbol. } catch(ExceptionElementoDuplicado ed_e) { System.size(). for(i = 0.obtenerPosicionRaiz())). } catch(ExceptionDesbordamientoVector dv_e) { System.getMessage()).print(recorrido. System.println("\nNumero de elementos: "+arbol. } } } Con las instrucciones del inicio de nuestro pequeño ejemplo (hasta antes de la marca de borrar un elemento) se crea un árbol como el mostrado en la siguiente figura: G E N D F J O Q Figura 10.getMessage()).obtenerAltura(arbol.print("\nRecorrido Postorden: ").err.recorrido = arbol.println(ne_e.obtenerPosicionRaiz())).err. .

E .Q D .Q .print” que están antes de la marca de borrar elemento nos ayudan a comprobar que lo que se muestra en la Figura 11 es cierto.J .G – 8 7 3 .J .E . 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 .N .O .out.Q D .F .G .F .Y las instrucciones “System.F .D .J .O .O .N .N .

F . La definición de nuestra clase persona sería la que se muestra en la Figura 13.E .beans.neos.D .Q D .Nombre: package org.Nombre).out. Árbol después de borrar el elemento “N” del árbol de la Figura 11. Y las instrucciones “System.O . una dirección (clase org. org. Clase Persona Esta clase esta compuesta por un nombre (clase org.print” que están despues de la marca de borrar elemento nos ayudan a comprobar que lo que se muestra en la Figura 12 es cierto.Direccion) y un atributo cadena llamado telefono.E .beans.G .F .J .neos.beans.Q . 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 .beans.O .neos. .Q D .F .O .J . El código de estas clases es: Clase org. public class Nombre { private String nombre.neos.E .Después de la marca borrar elemento. la estructura de nuestro árbol cambia a la mostrada en la siguiente figura: G E O D F J Q Figura 12.beans::Persona -nombre : Nombre -direccion : Direccion -telefono : String Figura 13.G – 7 6 2 Y como fue a mí a quien se le ocurrió la brillante idea de poner el Wrapper para la información 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í.J .

} public boolean equals(Object nombre) { Nombre _nombre = (Nombre)nombre. public Nombre(String nombre. private String materno. String a_pat = _nombre.getNombre() ) && paterno. if(com_ap == 0) { com_ap = materno. if(com_ap == 0) { return this.getMaterno() ) ) { return true.equals(_nombre.getPaterno() ) && materno.equals(_nombre. } } else { return com_ap. String paterno. } public String getPaterno() { return paterno.getNombre(). int com_ap = paterno. } } } . String a_mat = _nombre. } public void setMaterno(String string) { materno = string. } public void setPaterno(String string) { paterno = string.getMaterno(). String nom = _nombre. } public String getNombre() { return nombre.nombre. } else { return false.nombre = nombre.compareTo(nom). this.compareTo(a_mat). if( this. } else { return com_ap.paterno = paterno.getPaterno(). this. String materno) { this.materno = materno.equals(_nombre. } } public int compareTo(Object nombre) { Nombre _nombre = (Nombre)nombre. } public void setNombre(String string) { nombre = string.nombre.private String paterno. } public String getMaterno() { return materno.compareTo(a_pat).

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

} public Direccion getDireccion() { return direccion. } public int compareTo(Object persona) { Persona _persona = (Persona)persona.beans. public class Informacion { private Persona contenido.beans. Ahora lo único que tenemos que hacer es adaptar nuestra Clase org.Persona.direccion = direccion. } } return respuesta.getNombre().binarios.neos. " + nombre.getMaterno() + ". import org. } public void setTelefono(String string) { telefono = string. private Direccion direccion. this.Informacion para que su contenido sea un objeto de tipo org.beans. String telefono) { this.direccion = direccion.getNombre() ). } public String toString() { String respuesta = nombre. .private Nombre nombre.getPaterno() + " " + nombre.estaticos. } public String getTelefono() { return telefono. Direccion direccion. } public void setNombre(Nombre nombre) { this.neos. private String telefono.binarios.beans.nombre = nombre. this.arboles.telefono = telefono. } public boolean equals(Object persona) { Persona _persona = (Persona)persona.getNombre() ).equals(_persona. } public Nombre getNombre() { return nombre. return nombre.compareTo(_persona.estaticos.neos.Persona: package org. } public void setDireccion(Direccion direccion) { this. public Persona(Nombre nombre.nombre = nombre.neos.arboles. return nombre.

junto con sus métodos equals(Object) y compareTo(Object) (así como se hizo aquí con persona). import org.neos.util.getContenido()).contenido = (Persona)contenido.arboles. public class Ejemplo { .beans. 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 información que queremos contener en nuestro árbol.estaticos. } else { return false.estaticos.arboles.neos.binarios.beans.estaticos. } public void setContenido(Object contenido) { this.ExceptionDimensionInvalida. Ya que se ha definido la clase que define la información que va a contener el árbol y como se compara esta información (en org. A continuación se muestra un pequeño ejemplo: package org.neos. import java.Nombre.neos.binarios.binarios.arboles. import org. import org.ExceptionElementoDuplicado.arboles.arboles. import org.binarios.binarios.neos.estaticos.Persona.binarios. } public boolean equals(Object info) { Informacion _info = (Informacion)info.compareTo(_info. import org.estaticos.neos.arboles.public Informacion(Object contenido) { this.exceptions.exceptions.beans.beans.equals(_info.exceptions. } } return contenido.ExceptionDesbordamientoVector.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.contenido = (Persona)contenido. } } public int compareTo(Object info) { Informacion _info = (Informacion)info.ArrayList. Y ya que se tenga definida la clase de nuestra información se debe importar esta en la clase org.neos. } public Object getContenido() { return contenido.getContenido()) ) { return true.estaticos.Informacion) podemos comenzar a usar nuestro árbol.neos.Direccion. if( contenido. import org.beans.neos.

nombre = new Nombre("Eugenio". "Hidalgo".err.insertarElemento(persona). for(i = 0. null).out.").obtenerNumeroElementos(arbol. for(i = 0.out.obtenerPosicionRaiz()). System. "Flores". "Barrera"). direccion. direccion. arbol. arbol.err. int i.get(i) + " . direccion.println(ed_e.println("\nNumero de elementos: "+arbol. } } } .insertarElemento(persona).print((Persona)recorrido.println(dv_e. num_elems = recorrido.out. persona = new Persona(nombre.print((Persona)recorrido. null)."). recorrido = arbol. "Flores". "Martinez").recorridoPostorden(arbol.getMessage()).obtenerPosicionRaiz())).err. "Vazquez".out. i < num_elems. System. num_elems.get(i) + " . nombre = new Nombre("Hector". null).err. num_elems = recorrido. "Matinez").out. nombre = new Nombre("Miguel".obtenerPosicionRaiz())). num_elems = recorrido. } recorrido = arbol. nombre = new Nombre("Nayeli". 1.size(). null). persona = new Persona(nombre. "B-1". persona = new Persona(nombre.out. System. i++) { System. Persona persona = null.get(i) + " .insertarElemento(persona). for(i = 0.obtenerPosicionRaiz()).print("\nRecorrido Inorden: "). i < num_elems. System. arbol. System. persona = new Persona(nombre. i < num_elems.recorridoPreorden(arbol. Nombre nombre = null. } catch(ExceptionDesbordamientoVector dv_e) { System.public static void main(String[] args) throws ExceptionDimensionInvalida { ArbolBinarioEstatico arbol = new ArbolBinarioEstatico(27).size().print("Recorrido Preorden: "). direccion.obtenerAltura(arbol. null). "Hidalgo". direccion.insertarElemento(persona). "EEE"). i++) { System.println("Peso del árbol: "+arbol. arbol. "DDD".getMessage()). i++) { System.obtenerPeso(arbol. arbol. "CCC".print("\nRecorrido Postorden: ").obtenerPosicionRaiz())). nombre = new Nombre("Mario".println("Altura del árbol: "+arbol.insertarElemento(persona).print((Persona)recorrido. try { direccion = new Direccion("AAA". "Vasquez").err. persona = new Persona(nombre.obtenerPosicionRaiz()). "Barrera"). ArrayList recorrido = null. } catch(ExceptionElementoDuplicado ed_e) { System. } recorrido = arbol.recorridoInorden(arbol. } System. Direccion direccion = null.").size().

y más concretamente a las listas. Eugenio . Hector .Hidalgo Martinez.Vazquez Vasquez. Árbol construido con el ejemplo anterior Y para demostrar que lo que muestra la figura es cierto. Nayeli Hidalgo Martinez.Vazquez Vasquez. Eugenio . Miguel . Implementación dinámica de un árbol binario Si añadimos a los árboles la restricción de que cada elemento puede tener un solo posterior.Hidalgo Matinez.Hidalgo Martinez. Lo que debe desplegar nuestro pequeño ejemplo es lo siguiente: Recorrido Preorden: Flores Barrera. Mario .Hidalgo Martinez. Miguel . Miguel Hidalgo Martinez. Hugo Flores Barrera.Con las instrucciones del inicio de nuestro pequeño ejemplo se crea un árbol como el mostrado en la siguiente figura: Flores Barrera. Hector . Eugenio Numero de elementos: 5 Peso del árbol: 4 Altura del árbol: 3 Y con esto terminamos la implementación de nuestro árbol dentro de un vector… Ya solo resta que ustedes vean si les es útil e implementarlo. Miguel .Vazquez Vasquez. Mario Figura 14.Hidalgo Matinez. Nayeli Recorrido Postorden: Flores Barrera. Así pues. Mario Recorrido Inorden: Flores Barrera.Flores Barrera. las listas no son más que un caso particular de los árboles. Nayeli .Hidalgo Matinez. Hector .Flores Barrera. Eugenio Vazquez Vasquez. Mario .Flores Barrera. En este punto. si añadimos ciertas restricciones de acceso a las listas llegamos . Nayeli . llegamos a las estructuras lineales.

de modo que al formar nuestro árbol dinámico se armaría una estructura más o menos parecida a la mostrada en la figura: Padre Información Izq Der Padre Información Izq Der Padre Información Izq Der Figura 16. Así que se han implementado una lista dinámica lo que vamos a ver debe ser fácil. colas pilas. En esta ocasión no voy a describir los métodos ya que estamos reciclando el código que se genero para el árbol en el vector. Por lo tanto. Y como vamos a reciclar el código que generamos para el árbol dentro del vector será más parecido a una lista doblemente ligada.a las colas o a las pilas. La estructura de nuestro nodo sigue siendo la misma que la de la Figura 7 y el mostrado en la siguiente figura: NODO Padre Información Izq Der Figura 15. son tipos particulares de listas. Estructura del árbol dinámico Bueno. pues entonces vamos a ver la definición en Java de la clase que representará nuestro árbol. por lo tanto es muy parecido y creo que lo entenderán para que sirve cada método si lo relacionan con los métodos del árbol visto anteriormente :-) . 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).

import import import import org.binarios. } else { Informacion obj_info = new Informacion(info).dinamicos.Nodo. } else { return false.ExceptionElementoDuplicado. org. org. raiz). public boolean esArbolVacio() { return (null == raiz) ? true : false.beans. this.neos.arboles.recorrido } = null.exceptions.arboles.neos.binarios.binarios. private ArrayList recorrido.beans.dinamicos. public ArbolBinario() { this. Nodo raiz) { if(null == raiz) { return raiz. } } public Nodo obtenerElemento(Object info.arboles.dinamicos.dinamicos.Informacion.getInformacion() ).arboles.package org.neos.ArrayList. org.binarios. public class ArbolBinario { private Nodo raiz. Informacion obj_info_pa = new Informacion( raiz.arboles.util.neos. import java.raiz = null. .binarios.dinamicos. } public boolean existeElemento(Object info) { Nodo nodo = obtenerElemento(info.exceptions. } public Nodo obtenerPosicionRaiz() { return raiz.neos. if(null != nodo) { return true.ExceptionNoEncontrado.

getIzquierdo()). } } return num_elems.getDerecho()).getDerecho()).compareTo(obj_info_pa) < 0 ) { return obtenerElemento(info. peso = num_h_izq + num_h_der. } } public int obtenerAltura(Nodo nodo) { int altura = 0.getDerecho()). raiz. public int obtenerPeso(Nodo nodo) { int peso = 0. return peso. int num_h_izq = 0. if(null != nodo) { num_h_izq = obtenerNumeroElementos(nodo. // contabilizar el nodo visitado num_elems += obtenerNumeroElementos(nodo. } else if( obj_info. raiz. int num_h_der = 0. num_h_der = obtenerNumeroElementos(nodo. if(null != nodo) { num_elems += obtenerNumeroElementos(nodo.getIzquierdo()).if( obj_info_pa. . Nodo ref_h_izq. num_elems++. } else { return obtenerElemento(info.equals(obj_info) ) { return raiz. } } } public int obtenerNumeroElementos(Nodo nodo) { int num_elems = 0. int altura_r_izq = 0. Nodo ref_h_der.getIzquierdo()).

if( obj_info. altura_r_der = obtenerAltura(ref_h_der). Informacion obj_info = new Informacion(info). if(altura_r_izq >= altura_r_der) { altura += altura_r_izq.compareTo(obj_info_pa) < 0 ) { if(nodo. Informacion obj_info_pa = new Informacion( nodo. } } else if( (ref_h_izq != null) && (ref_h_der == null) ) { altura += obtenerAltura(ref_h_izq).getDerecho(). nuevo_nodo.getInformacion() ). nodo.int altura_r_der = 0. } else if( (ref_h_izq == null) && (ref_h_der != null) ) { altura += obtenerAltura(ref_h_der).getIzquierdo()). if(null != nodo) { altura = 1. private boolean insertarElemento(Object info. } } } return altura. ref_h_izq = nodo. } else { altura += altura_r_der.getIzquierdo(). Nodo nodo) { Nodo nuevo_nodo = null. } else if( (ref_h_izq == null) && (ref_h_der == null) ) { altura -= 1.setIzquierdo(nuevo_nodo). } else { return insertarElemento(info.getIzquierdo() == null) { nuevo_nodo = new Nodo(info). if( (ref_h_izq != null) && (ref_h_der != null) ) { altura_r_izq = obtenerAltura(ref_h_izq).setPadre(nodo). nodo. } . return true. ref_h_der = nodo.

nodo. } else { se_inserto = insertarElemento(info.getDerecho() != null) ) { . nuevo_nodo.} else { if(nodo. } } } return se_inserto. nodo. return true.raiz = new Nodo(info).getPadre() != null) { if( (nodo.setDerecho(nuevo_nodo). if( this. public boolean borrarElemento(Object info) throws ExceptionNoEncontrado { Nodo nodo = null.setPadre(nodo).esArbolVacio() ) { this. if( this. } } } public boolean insertarElemento(Object info) throws ExceptionElementoDuplicado { boolean se_inserto = false.getIzquierdo() != null) || (nodo.getDerecho()). if(nodo. } else { return insertarElemento(info. } else { if( existeElemento(info) ) { nodo = obtenerElemento(info.esArbolVacio() ) { throw new ExceptionNoEncontrado("El árbol esta vacío!!"). raiz). } else { if( existeElemento(info) ) { throw new ExceptionElementoDuplicado("El elemento ya existe dentro del árbol!!").getDerecho() == null) { nuevo_nodo = new Nodo(info). se_inserto = true. boolean se_borro = false. raiz).

nodo_der).getIzquierdo() != null) && (nodo.setDerecho(nodo_izq. nodo = null.setDerecho(nodo_der).getDerecho().getIzquierdo() == nodo) { nodo_padre. nodo_c = new Nodo(nodo_izq. } } else { se_borro = borrarNodoRaiz(nodo). } } } return se_borro. Nodo nodo_c = null.setPadre(nodo_padre). Nodo nodo_izq = nodo. if( (nodo.getDerecho() != null) ) { if(nodo_padre. Nodo nodo_padre = nodo.setIzquierdo(nodo_der). nodo_izq = null.getInformacion(). } else { se_borro = borrarNodoHoja(nodo).se_borro = borrarNodoInterior(nodo). } else if(nodo. if(nodo_padre.getIzquierdo() != null) { nodo_izq. insertarElemento(nodo_c. } } else { throw new ExceptionNoEncontrado("El elemento no existe dentro del árbol!!").getPadre().setIzquierdo(nodo_izq. respuesta = true.getDerecho()). nodo_c. Nodo nodo_der = nodo.getIzquierdo()). nodo_c.getIzquierdo().getInformacion()).getDerecho() == nodo) { . private boolean borrarNodoInterior(Nodo nodo) { boolean respuesta = false.setPadre(nodo_padre). } nodo_der. } else { nodo_padre.

} else { nodo_padre.getDerecho().setDerecho(nodo_der).getIzquierdo() != null) && (nodo. Nodo nodo_c = null. .nodo_padre.setIzquierdo(null). } nodo = null.setDerecho(nodo_izq). respuesta = true. } else { nodo_padre.getDerecho() != null) ) { this. se_borro = true. } private boolean borrarNodoHoja(Nodo nodo) { boolean se_borro = false. Nodo nodo_izq = nodo.setDerecho(null). if(nodo_padre.getIzquierdo().raiz = nodo_der. if(nodo_padre.getDerecho() == nodo) { nodo_padre. } return se_borro. Nodo nodo_der = nodo. } return respuesta. } else { nodo_der. } nodo = null. if( (nodo.getDerecho() == nodo) { nodo_padre. } else { nodo_padre.setIzquierdo(nodo_der).setIzquierdo(nodo_izq). } nodo = null. Nodo nodo_padre = nodo. respuesta = true.getPadre(). private boolean borrarNodoRaiz(Nodo nodo) { boolean se_borro = false.setPadre(nodo_padre).

nodo_c.setPadre(null).setPadre(null). se_borro = true. raiz).raiz. se_borro = true.setIzquierdo(nodo_izq.this.raiz = null. } public ArrayList recorridoPreorden(Nodo nodo) { if(nodo == raiz) { recorrido = new ArrayList(). } else { this. } if(null != nodo) { recorrido. nodo_c. se_borro = true. nodo_izq = null. recorridoPreorden(nodo.raiz.getIzquierdo()). } else if(nodo.getIzquierdo() != null) { this.getDerecho()).getIzquierdo()).getDerecho()). se_borro = true.getInformacion()). nodo_c = new Nodo(nodo_izq.getDerecho() != null) { this.raiz.raiz = nodo_der.add(nodo.setDerecho(nodo_izq.getInformacion()). this. } public ArrayList recorridoInorden(Nodo nodo) { . this. nodo = null. nodo = null. } else if(nodo.raiz = nodo_izq. nodo = null. recorridoPreorden(nodo. insertarElemento(nodo_c. } return se_borro.setPadre(null). } return recorrido.

} } Y bueno.binarios.arboles.dinamicos.neos. org.add(nodo.neos. El código de nuestro ejemplo es el código del último ejemplo del árbol contenido en el vector. org. recorridoPostorden(nodo.getDerecho()). o que por lo menos lo funciona lo esencial. import import import import org.util.getIzquierdo()). org.Direccion.neos.add(nodo. } if(null != nodo) { recorridoInorden(nodo.beans. } public ArrayList recorridoPostorden(Nodo nodo) { if(nodo == raiz) { recorrido = new ArrayList().getDerecho()).exceptions. recorridoInorden(nodo.getIzquierdo()).if(nodo == raiz) { recorrido = new ArrayList(). solo que utilizando nuestro árbol dinámico.beans. recorrido. para demostrar que este funciona.getInformacion()).neos. package org.ExceptionElementoDuplicado.arboles.getInformacion()). pues el ya tan tradicional pequeño ejemplo que utiliza nuestro árbol.dinamicos.ArrayList. por lo que utiliza las mismas clases que se usaron en el ejemplo anterior para almacenar la información.binarios. public class Ejemplo { .neos. recorrido. } return recorrido.Persona.beans. import java. } if(null != nodo) { recorridoPostorden(nodo. } return recorrido.Nombre.

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

Miguel .Flores Barrera. Algo que se me ocurre para implementar este método es vaciar todos los elementos del árbol a un vector (en el vector los elementos estarían ordenados de menor a mayor) y después volver a reconstruir todo el árbol tomando como raíz el elemento que se encuentra a la mitad del vector.println("\nNumero de elementos: "+arbol.Hidalgo Martinez. Nayeli .err. para eliminar las modificaciones que tenemos que hacer a la clase “Informacion” cada ves que queremos que el árbol almacene otro tipo de información. Miguel .err.println("Altura del árbol: "+arbol. Otra opción.obtenerPosicionRaiz())).obtenerNumeroElementos(arbol. con los elementos más pequeños. Mario . y una derecha. con los elementos más grandes) por lo tanto debemos hacer lo mismo para la parte izquierda y la parte derecha (tomar el elemento del centro como raíz) de manera recursiva hasta terminar con ambas partes del vector.obtenerPeso(arbol.obtenerPosicionRaiz())). } catch(ExceptionElementoDuplicado ed_e) { System. Nayeli .Hidalgo Matinez. Y para demostrar que lo que muestra la figura es cierto.Vazquez Vasquez. Hector .Hidalgo Matinez. Otra muy buena mejora a nuestro árbol sería hacerlo independiente de la información que almacena y que siguiera teniendo la información ordenada. System.Vazquez Vasquez. Hector . aun mejor. } } } Con nuestro pequeño ejemplo se crea un árbol como el mostrado en la Figura 14.Hidalgo Martinez.println("Peso del árbol: "+arbol.err. Eugenio . Nayeli Recorrido Postorden: Flores Barrera.} System. Eugenio Numero de elementos: 5 Peso del árbol: 4 Altura del árbol: 3 Algo que podríamos hacer para mejorar nuestro árbol sería implementar un método que permita balancear nuestro árbol para que no tengamos una rama más larga que otra y de esta forma tratar de optimizar búsquedas e inserciones. Hector . Miguel . System.Vazquez Vasquez.err.getMessage()).Hidalgo Matinez.Flores Barrera.println(ed_e. Mario Recorrido Inorden: Flores Barrera. .obtenerAltura(arbol.Hidalgo Martinez. Eugenio . al tomar el elemento del centro nuestro vector se dividiría en dos partes (una izquierda. Mario .Flores Barrera. sería implementar los algoritmos para árboles equilibrados (AVL).obtenerPosicionRaiz())). Lo que debe desplegar nuestro pequeño ejemplo es lo siguiente: Recorrido Preorden: Flores Barrera.

Sign up to vote on this title
UsefulNot useful