Estructuras de Datos y Algoritmos. Curso 2004/05 Tema 6. ´ Arboles y ´ Arboles Binarios
Mabel Galiano Natividad Prieto
Departamento de Sistemas Inform´ aticos y Computaci´ on Escuela T´ ecnica Superior de Inform´ atica Aplicada
´Indice
1. Introducci´on a las Estructuras Jer´arquicas: ´Arboles 2 1.1. Conceptos generales . . . 3 1.2. ´Arboles Binarios: definici´on, propiedades y tipos de Recorrido . . . 4 1.3. Representaci´on Contigua de un ´Arbol Binario Completo . . . 8 1.4. Representaci´on Enlazada de un ´Arbol Binario General: el concepto de Nodo Binario 9 2. Implementaci´on en Java de un ´Arbol Binario General 9 2.1. La clase ArbolBinario . . . 9 2.2. La clase NodoBinario . . . 10
Objetivos y Bibliograf´ıa
El objetivo general de este tema es introducir y estudiar el Arbol Binario´ como la estruc- tura jer´arquica b´asica a partir de la cual se obtienen tanto el Mont´ıculo BinariooHeapcomo el Arbol Binario de B´´ usqueda, que se presentar´an m´as tarde en la asignatura como posibles Im- plementaciones de alguno de los Modelos avanzados, bien Cola de Prioridad o bien Diccionario.
Para ello, a partir de los conceptos generales asociados al ´Arbol, se definir´a el ´Arbol Binario, sus propiedades y operaciones tanto b´asicas como de Recorrido (In-Orden, Pre-Orden, Post-Orden y Por Niveles). Adem´as, se presentar´an sus dos Representaciones posibles: contigua para un Arbol Binario Completo, que se utilizar´´ a para representar un Mont´ıculo, y enlazada para un Arbol Binario general, que ser´´ a el fundamento de la Representaci´on de los ´Arboles Binarios de B´usqueda y en funci´on de la cual se dise˜nar´a en Java la clase ArbolBinario que representa un Arbol Binario general mediante un ´´ unico Enlace a su Nodo ra´ız, esto es como una estructura Enlazada de Objetos de la clase NodoBinario.
Como bibliograf´ıa b´asica de este tema se utilizar´an los siguientes cap´ıtulos y apartados del libro de Weiss, M.A. Estructuras de datos en Java: el apartado 5 del cap´ıtulo 6 para la introducci´on de las estructuras de ´Arbol y ´Arbol Binario y los apartados del 1 al 3 del cap´ıtulo 17 para lo referente a las clases Java ArbolBinario y NodoBinario.
1. Introducci´ on a las Estructuras Jer´ arquicas: ´ Arboles
En ocasiones los Datos de una Colecci´on mantienen relaciones de tipo Jer´arquico que no es posible expresar mediante una Representaci´on Lineal de la Colecci´on, como la Lista Enlaza- da Indirecta o el simple array estudiadas en el tema anterior. Por ejemplo, son claramente jer´arquicas las relaciones que mantienen los distintos directorios, y ficheros, en los que se or- ganiza la informaci´on de un Sistema Operativo o los operadores y operandos que conforman una expresi´on aritm´etica a evaluar durante la compilaci´on o interpretaci´on de un programa.
En estos casos, la forma m´as natural de representar la Colecci´on es la de Arbol,´ la estructura Jer´arquica por excelencia; la siguiente figura muestra gr´aficamente el ´Arbol que representa la Colecci´on de Directorios de las pr´acticas de EDA a partir del directorio home de un usuario:
$HOME
EDA
libJava progJava
estructurasDeDatos util misFiguras bancoDeModems
lineales jerarquicos hashing
En cuanto a la expresi´on aritm´etica (((a*b)+(c+d))*(e-f)), en notaci´on infija y parenti- zada, se muestra a continuaci´on el ´Arbol que la puede representar:
− +
d
* b
a c
e f
+
*
Muy importante tambi´en para los prop´ositos de la asignatura resulta destacar que la es- tructura en ´Arbol, adem´as de representar las relaciones jer´arquicas existentes entre los Datos de una Colecci´on, puede favorecer la B´usqueda Din´amica caracter´ıstica de los Modelos Cola de Prioridad y Diccionario en tiempos sublineales, que como es sabido no consigue su Rep- resentaci´on Lineal. Por ejemplo, si se desea representar la Colecci´on de Palabras mes, mesa, meta, metro, coro y corona cualquier estructura Lineal requiere un tiempo de B´usqueda del orden del n´umero de Palabras que la forman, mientras que el ´Arbol de Palabras (Trie) que se muestra a continuaci´on s´olo exige un tiempo proporcional a la longitud de la Palabra buscada:
m e s a
t
c o r
o n a r
o a
Otro ejemplo significativo de B´usqueda Din´amica eficiente es el que se consigue con ´Arboles como el que muestra la siguiente figura y que representa la Colecci´on de Integer 100, 50, 200, 25, 75, 150, 300 y 180:
100
200
25 75 150 300
50
180
En este ´Arbol, cara a favorecer cualquier proceso de B´usqueda Binaria (insertar, borrar o buscar un Dato), los Integer de la Colecci´on se disponen de la siguiente forma ordenada: el primero, el 100, ocupa la Ra´ız del ´Arbol y a partir de ´esta, cada Dato menor que el primero se sit´ua en la parte izquierda del ´Arbol y cada Dato mayor en la derecha; adem´as, para cada sub- Arbol o parte de ´´ este, el proceso se repite. Por ejemplo, el Dato 75 al ser menor que 100 pero mayor que 50 se sit´ua a la izquierda de la Ra´ız, ocupada por 100, y a la derecha del sub- ´Arbol cuya Ra´ız ocupa 50; con ello bastar´an 2 comparaciones para encontrar el Integer 200 en el Arbol. ´´ Arboles de este tipo, denominados ´Arboles Binarios de B´usqueda, se estudiar´an m´as adelante con detalle para conocer bajo qu´e condiciones espec´ıficas garantizan una B´usqueda Din´amica con coste logar´ıtmico.
1.1. Conceptos generales
Un Arbol´ es una estructura Jer´arquica que se puede definir por medio de un conjunto de Nodos, uno de los cuales es distinguido como la Ra´ız del ´Arbol, y un conjunto de Aristas tal que cualquier Nodo H, a excepci´on de la Raiz, est´a conectado por medio de una Arista a un
´unico Nodo P; se dice entonces que P es el Padre de H y H es un Hijo de P. Si un Nodo no tiene ning´un Hijo se denomina Hoja; excluidas las Hojas, al resto de Nodos del ´Arbol, los que tienen alg´un Hijo, se les denomina Internos. Para ejemplificar las definiciones realizadas, en la siguiente figura se muestra un ´Arbol con 14 Nodos etiquetados con las Letras de la A a la N:
I M B
D E F G H
C A
L K J N
Figura 1: ´Arbol Ejemplo con 14 Nodos
N´otese que el Nodo etiquetado como A es la Ra´ız del ´Arbol y B y C son sus Hijos; el Nodo etiquetado con C es el Padre de los Nodos F, G y H y el Nodo I tiene dos Hijos etiquetados como
M y N. Asimismo, los Nodos con las etiquetas D, M, N, F, J, K y L son Hojas y el resto Nodos Internos.
Caminos entre Nodos: Profundidad, Nivel y Altura de un Nodo
Un ´Arbol se caracteriza porque desde la Ra´ız a cada uno de los Nodos hay un Camino´unico cuyaLongitudviene dada por el n´umero de Aristas que lo componen. Por ejemplo, en el ´Arbol de la Figura 1 el Camino desde la Ra´ız hasta la Hoja etiquetada como N es A-B-E-I-N y tiene longitud 4.
A partir de la Longitud de un Camino se definen la Profundidad, el Nivel y la Altura de un Nodo y un ´Arbol. Se denomina Profundidad de un Nodo a la Longitud del Camino que va desde la Ra´ız hasta ´el; por tanto, la Profundidad de la Ra´ız es 0. Adem´as, se dice que todos los Nodos que est´an a la misma Profundidad est´an en el mismo Nivel, siendo cero el de la Ra´ız. Por ejemplo, en la Figura 1 los Nodos D, E, F, G y H ocupan el Nivel 2, pues todos ellos tienen la misma Profundidad, tambi´en 2. Esta misma figura permite tambi´en observar que la representaci´on gr´afica que se hace de un ´Arbol es precisamente por Niveles, empezando por el de la Ra´ız, el cero, hasta el que ocupan las Hojas. Finalmente, la Altura de un Nodo se define como la Longitud del Camino que va desde dicho Nodo hasta la Hoja m´as profunda bajo ´el.
En base a esta definici´on, la Altura de un ´Arbol es la de su Nodo Ra´ız, 4 la del ´Arbol de la Figura 1.
Relaciones entre Nodos: Tama˜no de un Nodo
Utilizando la nomenclatura t´ıpica de la Genealog´ıa, a los Nodos de un ´Arbol que tienen el mismo Padre se les denomina Hermanos; as´ı, en el ´Arbol de la Figura 1 los Nodos F, G y H son Hermanos porque tienen el mismo Padre, el Nodo etiquetado con C. Asimismo, si hay un Camino desde el Nodo u hasta el Nodo v, se dice que u es un Ascendiente de v y que v es un Descendiente de u. Si u = v, entonces u es unAscendiente Propiode v y v es un Descendiente Propio de u; as´ı, en el ´Arbol ejemplo son Ascendientes Propios del Nodo etiquetado con N los Nodos I, E, B y A y son Descendientes propios de C los Nodos F, G, H, J, K y L.
En base a la nomenclatura que se acaba de introducir, el Tama˜no de un Nodo se define como el n´umero de Descendientes que tiene y el de un ´Arbol como el de su Nodo Ra´ız. Por ejemplo, el Tama˜no del Nodo C de la Figura 1 es 7, el del Nodo B es 6 y el del ´Arbol, i.e. el de su Nodo Ra´ız, es 14.
Definici´on Recursiva de un ´Arbol
Una definici´on de ´Arbol alternativa a la presentada es la recursiva. Seg´un ´esta, un ´Arbol es bien un ´Arbol vac´ıo o bien un Nodo Ra´ız y cero o m´as sub- ´Arboles no vac´ıos, cada una de cuyas Ra´ıces est´a conectada por medio de una Arista con la Ra´ız del ´Arbol.
Lo interesante de esta definici´on es que permite identificar el concepto de Nodo con el de Arbol:´ un Nodo define el ´Arbol del que es Ra´ız. Ser´a al hablar de ´Arboles Binarios cuando se explotar´a esta identificaci´on.
1.2. Arboles Binarios: definici´ ´ on, propiedades y tipos de Recorrido
UnArbol Binario´ es un ´Arbol en el que ning´un Nodo puede tener m´as de dos Hijos, que por ello pueden ser distinguidos comoHijo Izquierdo eHijo Derecho. N´otese c´omo el ´Arbol ejemplo que se ha venido utilizando hasta ahora, Figura 1, no es un ´Arbol Binario: tiene un Nodo, el etiquetado con C, que tiene 3 Hijos; sin embargo, el que muestra la siguiente figura s´ı lo es y
tiene 7 Nodos etiquetados: con A la Ra´ız, con B la Ra´ız de su Hijo Izquierdo y con C la de su Hijo Derecho (que a su vez, n´otese, s´olo tiene Hijo Izquierdo, que es el Nodo F).
B
D E F
C A
G
En la siguiente figura aparece un ´Arbol Binario que s´olo difiere del que se acaba de presentar en que su Nodo F es Hijo Derecho, y no Izquierdo, de C:
B
D E
A
G
C
F
Como se puede demostrar f´acilmente por Inducci´on, en un ´Arbol Binario de Altura H el n´umero m´aximo de Nodos del Nivel i es 2i, 0 ≤ i ≤ H. A partir de este resultado y en base a las definiciones previamente realizadas se pueden establecer los siguientes:
1. su n´umero m´aximo de Nodos es
i = 0 ... H 2i = 2H+1 − 1;
2. su n´umero m´aximo de Hojas es (2H+1 − 1) − (
i = 0 ... H-1 2i) = 2H; 3. su n´umero m´aximo de Nodos Internos es (2H+1 − 1) − (2H) = 2H − 1.
Arbol Binario Lleno y Completo´
Un ´Arbol Binario de Altura H es Lleno si tiene todos sus Niveles completos, esto es si en cada Nivel i, 0 ≤ i ≤ H, tiene exactamente 2i Nodos. Por ejemplo, el ´Arbol Binario de Altura 3 que muestra la siguiente figura es Lleno:
A partir de esta definici´on, en base a las propiedades expuestas para un ´Arbol Binario, es inmediato deducir que en un ´Arbol Binario Lleno de Tama˜no N y Altura H se cumplen las siguientes propiedades: H = log2 N y N = 2H+1 − 1.
Asimismo, se dice que un ´Arbol Binario es Completosi tiene todos sus Niveles completos a excepci´on quiz´as del ´ultimo que, entonces, debe de tener situados todos sus Nodos, las Hojas del ´Arbol, tan a la izquierda como sea posible; por ejemplo, el ´Arbol Binario que aparece en la siguiente figura es un ´Arbol Binario Completo:
N´otese que mientras un ´Arbol Binario Lleno es Completo no es cierta la afirmaci´on inversa, por lo que para la Altura y Tama˜no de un ´Arbol Binario Completo se cumplen, respectiva- mente, las siguientes desigualdades: H ≤ log2 N y 2H ≤ N ≤ 2H+1 − 1.
A modo de resumen, y para su uso posterior en la asignatura, conviene destacar ahora que la relaci´on expresada entre la Altura H y el N´umero de Nodos N de un ´Arbol Binario Completo (o Lleno) le confiere una caracter´ıstica muy importante: es Equilibrado, pues los N Datos de una Colecci´on se distribuyen en ´el de forma que la longitud de su Camino m´as largo, i.e. H, es a lo sumo log2 N.
Definici´on Recursiva de ´Arbol Binario
De forma an´aloga a la empleada para un ´Arbol, y como se expresa gr´aficamente en la siguiente figura, un ´Arbol Binario se define recursivamente bien como un ´Arbol Binario vac´ıo o bien como un Nodo Ra´ız y dos sub- ´Arboles Binarios, uno Izquierdo y otro Derecho, que pueden ser vac´ıos.
RAIZ
HIJO IZQUIERDO HIJO DERECHO
Figura 2: Representaci´on gr´afica de un ´Arbol Binario definido recursivamente
Esta definici´on resulta de gran utilidad para lograr implementar un ´Arbol Binario General, por lo que se emplear´a repetidamente en el resto del tema. En primer lugar, al identificar los conceptos de ´Arbol y Nodo, permite que un ´Arbol Binario se represente mediante un Enlace a su Nodo (Binario) Ra´ız y que, por tanto, las operaciones sobre un ´Arbol Binario sean opera- ciones que efectivamente se realizan, se lanzan, sobre su Nodo Ra´ız. En segundo lugar, aunque igualmente importante, proporciona una descomposici´on recursiva del ´Arbol Binario en base a la cual es posible dise˜nar f´acil y naturalmente la mayor´ıa de sus operaciones; a modo de ejemplo, obs´ervese que el Tama˜no o n´umero de Nodos del ´Arbol Binario que muestra la Figura 2 se define recursivamente bien como cero si el ´Arbol Binario es vac´ıo y sino como la suma del Tama˜no de su Ra´ız, esto es 1, y la del Tama˜no de sus Hijos Izquierdo y Derecho.
Operaciones de un ´Arbol Binario
A continuaci´on se clasifican en base a su coste las operaciones que se pueden realizar sobre un Arbol Binario, o equivalentemente sobre su Nodo (Binario) Ra´ız; al presentarlas se describir´´ an
de manera somera, reservando para la ´ultima secci´on de este tema la definici´on de sus perfiles y los detalles de su implementaci´on en Java:
1. Operaciones B´asicas o de coste del orden de una constante. Agrupadas por su funcionali- dad, ´estas son: dos constructoras, la de un ´Arbol Binario vac´ıo y la de una de sus Hojas, i.e. la de un ´Arbol con un ´unico Nodo Ra´ız compuesto por un Dato y dos Hijos vac´ıos; una modificadora, denominada uni´on, que dados dos ´Arboles Binarios arBinIzq y arbinDer y un Dato x obtiene como resultado un ´Arbol cuya Ra´ız contiene a x y cuyos Hijos son arBinIzq y arbinDer; finalmente, la ´ultima operaci´on B´asica es la t´ıpica consultora que comprueba si un ´Arbol Binario est´a vac´ıo.
2. Operacionesde Recorridocuyo coste es lineal con el N´umero de Nodos del ´Arbol visitados;
en particular, seg´un el orden en que se visitan los Nodos durante un Recorrido se pueden establecer los siguientes tipos:
de Recorrido en Anchura en el que los Nodos se visitan Nivel a Nivel y, dentro de un Nivel, siempre de izquierda a derecha. En base a esta definici´on es claro que la forma m´as natural de describirlas es la iterativa, funci´on que m´as tarde se explicitar´a durante el dise˜no del m´etodo Java imprimirPorNiveles, que a modo de toString obtiene en formato texto el Recorrido en Anchura de los Nodos de un Arbol Binario.´
de Recorridoen Profundidad en el que los Nodos se visitan bajando por las Ramas del ´Arbol y empezando siempre por la situada m´as a la izquierda; es por ello que, al contrario que lo que ocurr´ıa en el Recorrido en Anchura, la forma m´as natural de describirlo es la recursiva. N´otese que el c´alculo del Tama˜no y la Altura de un ´Arbol Binario suponen un Recorrido en Profundidad de ´este, lo mismo que la obtenci´on de la representaci´on en formato texto de sus Nodos (de nuevo toString pero en Profundidad) o la de su copia o la de su imagen sim´etrica o ...
Teniendo en cuenta que un Nodo se identifica con el ´Arbol del que es Ra´ız, seg´un la naturaleza de la operaci´on a realizar cada Nodo puede ser visitado durante un Recorrido en Profundidad de cualquiera de las tres formas siguientes: bienantesque los Hijos Izquierdo y Derecho oen Pre-Orden, bien despu´es que ´estos o en Post- Orden, bien despu´es que el Hijo Izquierdo yantes que el Derecho o en In-Orden.
Conviene mencionar ahora que tambi´en son posibles los Recorridos en Profundidad sim´etricos a los tres indicados, i.e. en los que se visita primero el Hijo Derecho y despu´es el Izquierdo.
Aplicando las definiciones de los cuatro tipos de Recorrido expuestos al ´Arbol Binario que muestra la siguiente figura,
B
A
C
F G
I
D E
H
J K
las diferentes secuencias de Nodos que se visitan durante cada uno de ellos son:
en In-Orden: D-B-E-H-A-F-C-J-I-K-G en Pre-Orden: A-B-D-E-H-C-F-G-I-J-K en Post-Orden: D-H-E-B-F-J-K-I-G-C-A Por Niveles: A-B-C-D-E-F-G-H-I-J-K
Es m´as, n´otese que si en lugar de Caracteres el ´Arbol Binario representa una expresi´on aritm´etica, sus Recorridos en In-Orden, Pre-Orden y Post-Orden corresponden, respec- tivamente, a las notaciones Infija, Prefija y Postfija de dicha expresi´on.
Cuesti´on:utilizando como ´Arbol ejemplo el que se acaba de mostrar, determ´ınese qu´e tipo de Recorrido en Profundidad requieren el c´alculo de su Altura, Tama˜no y la obtenci´on de un duplicado de ´el o copia.
1.3. Representaci´ on Contigua de un ´ Arbol Binario Completo
Como ya se ha indicado, un ´Arbol Binario Completo es un tipo especial de ´Arbol Binario pues en ´el los Datos de una Colecci´on se distribuyen de forma equilibrada. Adem´as de esta caracter´ıstica, se presenta en esta secci´on una propiedad igualmente importante, estructural, que ser´a utilizada en el siguiente tema para realizar la Implementaci´on eficiente de la EDA Cola de Prioridad: para representar un ´Arbol Binario Completo sin ambig¨uedad alguna basta con almacenar el resultado de su Recorrido por Niveles en un array.
21 16
31
24 19
65 26 32
13
1
2 3
4 5 6 7
8 9 10
1 2 3 4 5 6 7 8 9 10
0
13 21 16 24 31 19 68 65 26 32
68
Espec´ıficamente, como muestra la figura, el Dato que ocupa la Ra´ız del ´Arbol se sit´ua en la posici´on 1 del array (la cero se deja libre por motivos que se explicar´an m´as tarde), el primer Dato del primer Nivel en la 2, el segundo Dato del primer Nivel en la 3 y as´ı sucesivamente hasta que situar el ´ultimo Dato, el N-´esimo si N es el Tama˜no del ´Arbol, del Nivel H, el ´ultimo si H es la Altura del ´Arbol.
Con una Representaci´on como la descrita, que recibe el nombre de Impl´ıcita, no se necesita espacio adicional alguno para representar los dos Hijos del ´Arbol, s´olo el del array que almacena sus Datos y un ´ındice que indica su talla actual. En efecto, si la i-´esima componente del array, 1 ≤ i ≤ N, representa el i-´esimo Nodo (Ra´ız) de su Recorrido por Niveles entonces:
su Hijo Izquierdo se encuentra en la posici´on 2 ∗ i, siempre que 2 ∗ i ≤ N;
su Hijo Derecho se encuentra en la posici´on 2 ∗ i + 1, si 2 ∗ i + 1 ≤ N;
su Nodo Padre est´a en la posici´on i2 si i = 1, ya que la Ra´ız del ´Arbol es el ´unico Nodo que no tiene Padre; si lo tuviera, ocupar´ıa la posici´on cero del array, por lo que, precisamente, ´esta debe dejarse libre.
Adem´as de su destacada eficiencia, una ventaja adicional de la Representaci´on Impl´ıcita es que simplifica las operaciones de Recorrido del ´Arbol.
1.4. Representaci´ on Enlazada de un ´ Arbol Binario General: el concepto de Nodo Binario
Como ya se ha indicado, la definici´on recursiva de un ´Arbol Binario permite identificar cualquiera de sus Nodos con los (sub) ´Arboles Binarios de los que son Ra´ız; de donde resulta directo establecer que un ´Arbol Binario General sea representado ´unicamente mediante un Enlace a su Nodo Ra´ız. Para que la identificaci´on sea completa y congruente, la Representaci´on de un Nodo Binario, es decir de un Nodo de un ´Arbol Binario, debe constar de tres elementos:
un Objeto que representa el Dato que en ´el se sit´ue y un Enlace al Nodo Binario que es Ra´ız de su Hijo Izquierdo y otro al Nodo Binario Ra´ız de su Hijo Derecho, como se muestra en la siguiente figura:
dato NodoBinario
izq der
Figura 3: Estructura de un Nodo Binario
N´otese que mientras los Nodos de una Lista Enlazada Indirecta s´olo contienen un Enlace al siguiente, una Representaci´on Enlazada de un ´Arbol Binario requiere dos Enlaces, tantos como Hijos tiene el ´Arbol que representa.
2. Implementaci´ on en Java de un ´ Arbol Binario General
A partir de las operaciones y Representaci´on definidas previamente, en esta ´ultima secci´on se desarrollan las dos clases Java que implementan un ´Arbol Binario General: ArbolBinario y NodoBinario. Mientras que la primera se declarar´a p´ublica, por si se quisiera utilizar a- posteriori en aplicaciones t´ıpicas de los ´Arboles Binarios, la segunda es s´olo friendly pues, como se recordar´a, s´olo debe resultar visible a las clases que se desarrollar´an en temas posteriores como posibles implementaciones de los Modelos Avanzados Cola de Prioridad y Diccionario;
ambas se ubicar´an en el paquete jerarquicos del proyecto estructurasDeDatos de libJava.
2.1. La clase ArbolBinario
La clase Java ArbolBinario que se presenta a continuaci´on representa un ´Arbol Binario General mediante un ´unico Enlace a su Nodo Binario Ra´ız; por ello consta de un ´unico atributo NodoBinario raiz sobre el que la gran mayor´ıa de sus m´etodos (tamanyo, altura, etc.) se limitan a lanzar o invocar el correspondiente m´etodo de NodoBinario.
Adem´as de su simplicidad, resulta conveniente se˜nalar dos detalles m´as presentes en la codificaci´on de los m´etodos de ArbolBinario. En primer lugar, obs´ervese que la instrucci´on principal de su m´etodo unir, raiz = new NodoBinario(x, arBin1.raiz, arBin2.raiz), no se llega a ejecutar si los sub ´Arboles par´ametro arBin1 y arBin2 son iguales; si lo son, se lanza y propaga la Excepci´on UnionNoPermitida. Adem´as, en caso de ejecutarse se evita el posible aliasing entre dichos sub ´Arboles par´ametro y los Hijos del ´Arbol resultado de la uni´on:
si no se ejecutase arBin1.raiz = null cuando arBin1 != null, tanto arbin1.raiz como this.raiz.izq apuntar´ıan al mismo Nodo, lo mismo que arbin2.raiz y this.raiz.der si no
se ejecutara arBin2.raiz = null cuando arBin2 != null. En segundo lugar, los m´etodos de Recorrido siguen dos estilos de dise˜no distintos al lanzar el m´etodo hom´onimo de NodoBinario:
tamanyo, altura y duplicar lo hacen invocando a un m´etodo est´atico mientras que los distintos imprimir invocan a un m´etodo din´amico; como se puede observar ahora, y tambi´en en su implementaci´on en NodoBinario, la ´unica diferencia entre ambos tipos de m´etodos radica en c´omo tratan el caso de un Nodo o (sub) ´Arbol vac´ıo.
package jerarquicos;
import excepciones.*;
public class ArbolBinario { protected NodoBinario raiz;
public ArbolBinario() { raiz = null;}
public ArbolBinario(Object x) { raiz = new NodoBinario(x);}
public void unir(Object x, ArbolBinario arBin1, ArbolBinario arBin2) throws UnionNoPermitida {
if( arBin1.raiz == arBin2.raiz && arBin1.raiz != null )
throw new UnionNoPermitida("Los dos sub´Arboles son iguales; uni´on imposible !!!");
this.raiz = new NodoBinario( x, arBin1.raiz, arBin2.raiz );
/** Para evitar el aliasing, desreferenciar los sub´Arboles utilizados en la uni´on */
if( this != arBin1 ) arBin1.raiz = null;
if( this != arBin2 ) arBin2.raiz = null;
}
public boolean esVacio() { return ( this.raiz == null ); } public int tamanyo() { return NodoBinario.tamanyo(raiz);}
public int altura() { return NodoBinario.altura(raiz); } public void duplicar(ArbolBinario original){
if ( original.raiz != null ) this.raiz = original.raiz.duplicar();
}
public String imprimirPostOrden(){
if ( this.raiz != null ) return raiz.imprimirPostOrden(); else return "*";
}
public String imprimirPreOrden(){
if ( this.raiz != null ) return raiz.imprimirPreOrden(); else return "*";
}
public String imprimirInOrden(){
if ( this.raiz != null ) return raiz.imprimirInOrden(); else return "*";
}
public String imprimirPorNiveles(){
if ( this.raiz != null ) return raiz.imprimirPorNiveles(); else return "*";
} }
2.2. La clase NodoBinario
La clase Java NodoBinario representa un Nodo de un ´Arbol Binario, por lo que sus atributos ser´an tres (seg´un muestra la Figura 3): Object dato, que representa el Dato (de tipo gen´erico) que contiene el Nodo y dos Enlaces NodoBinario izq, der que representan, respectivamente, a sus Hijos Izquierdo y Derecho. N´otese tambi´en que en NodoBinario se re-utiliza el software desarrollado para implementar una Cola: el interfaz Cola del paquete modelos y la clase que lo implementa ArrayCola del paquete lineales; la raz´on es que su m´etodo imprimirPorNiveles implementa un Recorrido en Anchura de un Nodo que s´olo se puede realizar iterativamente, y no en base a su descomposici´on recursiva. Para ello, como ejemplifica el c´odigo propuesto, se debe utilizar como estructura auxiliar una Cola que inicialmente contiene el Nodo a recorrer por Niveles; mientras queden elementos en ella, el tratamiento que sistem´aticamente recibe su primer elemento o Nodo encolado es: tratar el Dato a ´el asociado, eliminarlo y, si no son
vac´ıos, encolar sus Hijos empezando por el Izquierdo. Obs´ervese que es al tratar la Cola cuando, indirectamente, se realiza el Recorrido iterativo por Niveles un Nodo.
package jerarquicos;
import modelos.*;
import lineales.*;
final class NodoBinario {
Object dato; NodoBinario izq, der;
NodoBinario(Object x) {this(x, null, null); }
NodoBinario(Object x, NodoBinario izquierdo, NodoBinario derecho) { dato = x; izq = izquierdo; der = derecho;
}
static int tamanyo(NodoBinario actual) { if ( actual == null ) return 0;
else return 1 + tamanyo(actual.izq) + tamanyo(actual.der);
}
static int altura(NodoBinario actual) { if ( actual == null) return -1;
else return (Math.max(altura(actual.izq), altura(actual.der)) + 1);
}
NodoBinario duplicar(){
NodoBinario raiz = new NodoBinario(this.dato);
if( this.izq != null ) raiz.izq = this.izq.duplicar( );
if( this.der != null ) raiz.der = this.der.duplicar( );
return raiz;
}
String imprimirPostOrden(){
String res = "";
if( this.izq != null ) res += izq.imprimirPostOrden( );
if( this.der != null ) res += der.imprimirPostOrden( );
res += dato.toString()+"\n";
return res;
}
String imprimirInOrden(){
String res = "";
if( this.izq != null ) res += this.izq.imprimirInOrden( );
res += dato.toString()+"\n";
if( this.der != null ) res += this.der.imprimirInOrden( );
return res;
}
String imprimirPreOrden(){
String res = dato.toString()+"\n";
if( this.izq != null ) res += this.izq.imprimirPreOrden( );
if( this.der != null ) res += this.der.imprimirPreOrden( );
return res;
}
String imprimirPorNiveles(){
String res = "";
Cola q = new ArrayCola();
q.encolar(this);
while ( !q.esVacia() ){
NodoBinario nodoActual = (NodoBinario)(q.desencolar());
res += nodoActual.dato.toString()+"\n";
if ( nodoActual.izq != null ) q.encolar(nodoActual.izq);
if ( nodoActual.der != null ) q.encolar(nodoActual.der);
}
return res;
} }
Ejercicios propuestos:
1. Se desean a˜nadir a la clase ArbolBinario nuevos m´etodos para realizar las siguientes operaciones:
obtener el n´umero de Hojas de un ´Arbol Binario;
obtener el ´Arbol Binario que es la imagen especular de uno dado;
visualizar la informaci´on asociada a los Nodos del Nivel k de un ´Arbol Binario;
comprobar si alg´un Nodo de un ´Arbol Binario contiene un Objeto dado x;
obtener el Nivel en el que est´a el Nodo que contiene un Objeto dado x.
Dis´e˜nense como invocaciones a sus hom´onimos de NodoBinario, est´aticos o din´amicos seg´un resulte m´as conveniente.
2. Modif´ıquese el m´etodo imprimirPorNiveles() de ArbolBinario para que muestre en l´ıneas diferentes los Nodos de cada Nivel.
3. Implem´entense de forma iterativa los m´etodos imprimirPreOrden(), imprimirInOrden() y imprimirPostOrden() de ArbolBinario.
4. Dis´e˜nese un m´etodo que obtenga el Padre de un Nodo de un ´Arbol Binario e ind´ıquese su coste Temporal ¿Se podr´ıa simplificar modificando la estructura de los Nodos?