Lectura 5-2 - Árboles Binarios
Lectura 5-2 - Árboles Binarios
Lectura 5-2 - Árboles Binarios
TABLA DE CONTENIDO
1. DEFINICIÓN 2
2. CONCEPTOS BÁSICOS 3
2.1. RELACIONES DE PARENTESCO ENTRE NODOS 3
2.2. HOJAS Y NODOS INTERNOS 3
2.3. CAMINOS Y RAMAS 4
2.4. DESCENDIENTES Y ANCESTROS 5
2.5. NIVEL 5
2.6. PESO Y ALTURA 5
2.7. ÁRBOLES DEGENERADOS, LLENOS, COMPLETOS Y PERFECTOS 6
3. IMPLEMENTACIÓN DE ÁRBOLES BINARIOS CON ÁRBOLES SENCILLAMENTE ENCADENADOS 7
3.1. CREACIÓN DE ÁRBOLES BINARIOS 9
3.2. MÉTODOS DE CONSULTA DE LOS ATRIBUTOS DE UN ÁRBOL BINARIO 10
3.3. MÉTODOS PARA CALCULAR EL PESO Y LA ALTURA DE UN ÁRBOL BINARIO 11
3.4. MÉTODOS DE BÚSQUEDA SOBRE UN ÁRBOL BINARIO 11
4. RECORRIDOS SOBRE ÁRBOLES BINARIOS 12
5. RECONSTRUCCIÓN DE UN ÁRBOL BINARIO A PARTIR DE SUS RECORRIDOS 15
5.1. RECONSTRUCCIÓN DE UN ÁRBOL BINARIO DADO SU INORDEN Y SU PREORDEN 16
EN RESUMEN 19
PARA TENER EN CUENTA 19
*
Resumen del libro Estructuras de Datos en Java de Alejandro Sotelo Arévalo, cuya publicación está pendiente.
ESTRUCTURAS DE DATOS 1
1. DEFINICIÓN
Un árbol binario es una estructura de datos recursiva que está compuesta por un valor,
llamado raíz, y por dos árboles, llamados subárbol izquierdo y subárbol derecho.
Formalmente:
1. El árbol que no posee ningún elemento, que representaremos gráficamente mediante el
símbolo , es un árbol binario denominado el árbol vacío.
2. Dado un valor val, y dos árboles binarios izq y der, se tiene que el árbol
val val : raíz
es un árbol binario cuya raíz es val, cuyo subárbol izquierdo es izq, y cuyo subárbol derecho
es der.
Observe que:
El árbol vacío no tiene raíz, no tiene subárbol izquierdo y no tiene subárbol derecho.
Todo árbol no vacío tiene raíz y tiene exactamente dos subárboles: el subárbol izquierdo y el
subárbol derecho. Es posible que uno o ambos subárboles sean vacíos.
El árbol vacío nunca puede ser considerado como nodo porque no es raíz de un árbol
binario no vacío.
ESTRUCTURAS DE DATOS 2
2. CONCEPTOS BÁSICOS
Las relaciones familiares se utilizan para nombrar relaciones típicas entre nodos:
ESTRUCTURAS DE DATOS 3
En otras palabras, un nodo es una hoja si sus dos subárboles son vacíos y es un nodo interno
si no es una hoja.
Un camino es una lista no vacía de nodos donde cada uno es padre del
que le sigue en la lista. La longitud de un camino es , o sea, el
número de nodos que enumera menos uno. Además, se define una rama como un camino
que parte de la raíz del árbol y llega a una hoja.
Siempre existe un camino de longitud que va desde un nodo hacia sí mismo, y siempre
existe un camino que va desde la raíz del árbol hasta cualquier nodo. A veces puede no existir
camino entre un par de nodos.
ESTRUCTURAS DE DATOS 4
2.4. DESCENDIENTES Y ANCESTROS
Tabla 8: Definición de ancestro y descendiente.
Relación Definición
Ancestro Un nodo es ancestro de un nodo si y sólo si hay camino que va de a .
Descendiente Un nodo es descendiente de un nodo si y sólo si es ancestro de .
2.5. NIVEL
El nivel de un nodo es la longitud del camino que va desde la raíz hasta el mismo nodo. Se
dice que un nivel está lleno si alberga la máxima cantidad posible de nodos que puede tener.
El nivel puede tener máximo un nodo, el nivel puede tener máximo dos nodos, el nivel
puede tener máximo cuatro nodos, el nivel puede tener máximo ocho nodos, y así
sucesivamente. En general, el nivel puede tener máximo nodos porque cada nivel aloja
máximo el doble de los nodos que el nivel anterior.
ESTRUCTURAS DE DATOS 5
Tabla 11: Ejemplos sobre el concepto de peso y altura.
Árbol binario Longitud de la rama más larga Peso ( ) Altura ( )
No tiene ramas.
Para todo árbol binario no vacío, su peso se puede calcular como uno más la suma de los
pesos de sus dos subárboles, y su altura se puede calcular como uno más el máximo entre las
alturas de sus dos subárboles. Dado un árbol con altura , el peso mínimo que puede tener
es y el peso máximo que puede tener es . Así mismo, dado un árbol con peso , la
altura mínima que puede tener es la parte entera de y la altura máxima que
puede tener es . ¿Por qué se cumple todo esto?
Tabla 12: Ejemplos que ilustran la máxima cantidad de nodos que pueden tener los árboles según su altura.
Árbol binario Peso ( ) Altura ( )
ESTRUCTURAS DE DATOS 6
Tabla 14: Ejemplos sobre los conceptos de árbol degenerado, árbol lleno, árbol completo y árbol perfecto.
Árbol binario ¿Degenerado? ¿Lleno? ¿Completo? ¿Perfecto?
SI SI SI SI
SI NO NO NO
NO SI NO NO
NO NO SI NO
NO SI SI NO
NO SI SI SI
La clase VEDArbin<E> representa un árbol binario de elementos de tipo E (Arbin abrevia Árbol
binario). Los atributos de la clase VEDArbin<E> son:
val: es una variable de tipo E que almacena el valor de la raíz del árbol.
izq: es una variable de tipo VEDArbin<E> que apunta al subárbol izquierdo del árbol.
der: es una variable de tipo VEDArbin<E> que apunta al subárbol derecho del árbol.
El árbol vacío se representa asignando null a los atributos val, izq y der, y los árboles no
vacíos se representan asignando valores distintos de null a los atributos val, izq y der, que
apuntan a la raíz, al subárbol izquierdo y al subárbol derecho, respectivamente.
Gráfica 15: Representación en memoria del árbol binario vacío, implementado con árboles sencillamente encadenados.
VEDArbin<E>
val
izq
der
ESTRUCTURAS DE DATOS 7
Gráfica 16: Representación en memoria del árbol binario no vacío,
implementado con árboles sencillamente encadenados.
VEDArbin<E>
val apunta a la raíz …
izq apunta al subárbol izquierdo …
der apunta al subárbol derecho …
En toda situación, los tres atributos tienen el valor null (cuando el árbol es vacío) o los tres
atributos tienen valores distintos de null (cuando el árbol no es vacío). Entonces, bajo la
estructura de datos, para diferenciar un árbol vacío de uno no vacío basta inspeccionar el
atributo val: si val es null es porque el árbol es vacío, y si val no es null es porque el árbol
no es vacío.
Gráfica 17: Representación interna de un árbol binario, implementado con un árbol sencillamente encadenado.
VEDArbin<E>
val 8
izq
árbol der
VEDArbin<E> VEDArbin<E>
val 5 val 3
izq izq
der der
ESTRUCTURAS DE DATOS 8
3.1. CREACIÓN DE ÁRBOLES BINARIOS
La clase VEDArbin<E> tiene dos métodos constructores: uno para crear un árbol vacío y otro
para crear un árbol no vacío a partir de su raíz, de su subárbol izquierdo y de su subárbol
derecho.
VEDArbin<E> provee métodos para exportar un árbol como texto o como imagen.
Específicamente,
System.out.println(arb.toString());
imprime en consola la representación textual del árbol arb según cierto formato que
definiremos más adelante, y la instrucción
arb.exportarComoImagen("ejemplo.png");
es capaz de exportar una imagen en formato .png con una representación gráfica del árbol
arb.
Tabla 20: Ejemplos que ilustran cómo construir árboles y cómo transformarlos en texto e imagen.
Imagen exportada
Programa
y texto impreso
VEDArbin<Integer> vacio=new VEDArbin<Integer>();
System.out.println(vacio.toString());
vacio.exportarComoImagen("ejemploCreacion01.png"); Ø
VEDArbin<Integer> vacio=new VEDArbin<Integer>();
VEDArbin<Integer> arb5=new VEDArbin<Integer>(5,vacio,vacio);
System.out.println(arb5.toString());
arb5.exportarComoImagen("ejemploCreacion02.png"); [5:Ø,Ø]
ESTRUCTURAS DE DATOS 9
VEDArbin<Integer> vacio=new VEDArbin<Integer>();
VEDArbin<Integer> arb89=new VEDArbin<Integer>(89,vacio,vacio);
VEDArbin<Integer> arb23=new VEDArbin<Integer>(23,vacio,arb89);
VEDArbin<Integer> arb10=new VEDArbin<Integer>(10,vacio,vacio);
VEDArbin<Integer> arb98=new VEDArbin<Integer>(98,arb23,arb10);
System.out.println(arb98.toString());
arb98.exportarComoImagen("ejemploCreacion03.png"); [98:[23:Ø,[89:Ø,Ø]],[10:Ø,Ø]]
VEDArbin<String> vacio=new VEDArbin<String>();
VEDArbin<String> arbA=new VEDArbin<String>("LUZ",vacio,vacio);
VEDArbin<String> arbB=new VEDArbin<String>("FÉ",vacio,arbA);
VEDArbin<String> arbC=new VEDArbin<String>("SOL",arbB,vacio);
System.out.println(arbC.toString());
arbC.exportarComoImagen("ejemploCreacion04.png");
[SOL:[FÉ:Ø,[LUZ:Ø,Ø]],Ø]
Código 22: Método para consultar el subárbol izquierdo del árbol binario.
public VEDArbin<E> getIzq() {
return izq; // Retornar el subárbol izquierdo.
}
Código 23: Método para consultar el subárbol derecho del árbol binario.
public VEDArbin<E> getDer() {
return der; // Retornar el subárbol derecho.
}
Código 24: Método para informar si el árbol binario es vacío o no, con complejidad temporal .
public boolean esVacio() {
if (val==null) { // Si la raíz es null:
return true; // Retornar true porque este árbol representa el árbol vacío.
}
else { // Si la raíz no es null:
return false; // Retornar false porque este árbol no representa el árbol vacío.
}
}
Código 25: Método para determinar si un nodo es una hoja o no, con complejidad temporal .
public boolean esHoja() {
if (esVacio()) { // Si este árbol es vacío:
return false; // Decir que este árbol no representa una hoja.
}
else { // Si este árbol no es vacío:
if (izq.esVacio()&&der.esVacio()) { // Si los dos subárboles son vacíos:
return true; // Decir que este árbol sí representa una hoja.
}
else { // Si alguno de los dos subárboles no es vacío:
return false; // Decir que este árbol no representa una hoja.
}
}
}
ESTRUCTURAS DE DATOS 10
3.3. MÉTODOS PARA CALCULAR EL PESO Y LA ALTURA DE UN ÁRBOL BINARIO
Código 26: Función que calcula el peso del árbol.
public int peso() {
if (esVacio()) { // Si este árbol es vacío:
return 0; // El peso del árbol vacío es 0.
}
else { // Si este árbol no es vacío:
// El peso de un árbol no vacío es uno más el peso del subárbol izquierdo más el
// peso del subárbol derecho:
return 1+izq.peso()+der.peso();
}
}
Para determinar el número de veces que aparece un valor dentro del árbol binario, se deben
inspeccionar todos los nodos del árbol, comparándolos contra el valor buscado.
ESTRUCTURAS DE DATOS 11
// Retornar uno más el número de ocurrencias en izq y en der:
return 1+contadorIzq+contadorDer;
}
else { // Si el objeto buscado no es igual a la raíz del árbol:
// Retornar el número de ocurrencias en izq y en der:
return contadorIzq+contadorDer;
}
}
}
El algoritmo tiene complejidad temporal porque procesa exactamente una vez cada
nodo.
Un recorrido de un árbol binario es un proceso que visita exactamente una vez cada uno de
los nodos del árbol, en cierto orden determinado. Existen muchas formas de recorrer un
árbol binario, entre estas:
Tabla 29: Resumen de los cuatro principales recorridos sobre árboles binarios.
Recorrido Esquema Descripción
Visita primero la raíz del árbol, luego recorre el subárbol
En preorden val-[izq]-[der] izquierdo en preorden, y después recorre el subárbol derecho
en preorden.
Recorre el subárbol izquierdo en inorden, luego visita la raíz del
En inorden [izq]-val-[der]
árbol, y después recorre el subárbol derecho en inorden.
Recorre el subárbol izquierdo en postorden, luego recorre el
En
[izq]-[der]-val subárbol derecho en postorden, y después visita la raíz del
postorden
árbol.
nivel0-…-nivelh- Visita los nodos nivel por nivel, desde el nivel hasta el nivel
Por niveles 1 , donde cada nivel se recorre de izquierda a derecha.
Todos los recorridos se pueden tratar como listas que enumeran los nodos del árbol en un
orden específico. Observe que los procesos descritos para hallar los recorridos en preorden,
en inorden y en postorden son recursivos, y que el proceso definido para el recorrido por
niveles es iterativo.
ESTRUCTURAS DE DATOS 12
Código 31: Método recursivo que halla el recorrido en preorden con complejidad temporal ,
donde es el peso del árbol.
public List<E> preorden() {
List<E> lista=new ArrayList<E>(); // Crear una lista nueva.
preorden(lista); // Alimentar la lista con el recorrido en preorden.
return lista; // Retornar la lista.
}
private void preorden(List<E> pLista) {
if (esVacio()) { // Si este árbol es vacío:
// No hacer ninguna operación.
}
else { // Si este árbol no es vacío:
pLista.add(val); // Añadir la raíz del árbol a la lista.
izq.preorden(pLista); // Recorrer el subárbol izquierdo en preorden.
der.preorden(pLista); // Recorrer el subárbol derecho en preorden.
}
}
Código 32: Método recursivo que halla el recorrido en inorden con complejidad temporal ,
donde es el peso del árbol.
public List<E> inorden() {
List<E> lista=new ArrayList<E>(); // Crear una lista nueva.
inorden(lista); // Alimentar la lista con el recorrido en inorden.
return lista; // Retornar la lista.
}
private void inorden(List<E> pLista) {
if (esVacio()) { // Si este árbol es vacío:
// No hacer ninguna operación.
}
else { // Si este árbol no es vacío:
izq.inorden(pLista); // Recorrer el subárbol izquierdo en inorden.
pLista.add(val); // Añadir la raíz del árbol a la lista.
der.inorden(pLista); // Recorrer el subárbol derecho en inorden.
}
}
Código 33: Método recursivo que halla el recorrido en postorden con complejidad temporal ,
donde es el peso del árbol.
public List<E> postorden() {
List<E> lista=new ArrayList<E>(); // Crear una lista nueva.
postorden(lista); // Alimentar la lista con el recorrido en postorden.
return lista; // Retornar la lista.
}
private void postorden(List<E> pLista) {
if (esVacio()) { // Si este árbol es vacío:
// No hacer ninguna operación.
}
else { // Si este árbol no es vacío:
izq.postorden(pLista); // Recorrer el subárbol izquierdo en postorden.
der.postorden(pLista); // Recorrer el subárbol derecho en postorden.
pLista.add(val); // Añadir la raíz del árbol a la lista.
}
}
ESTRUCTURAS DE DATOS 13
Para recorrer un árbol por niveles tenemos el siguiente algoritmo iterativo con complejidad
temporal :
1. Cree una cola vacía de árboles.
2. Inserte en la cola el árbol cuyo recorrido por niveles se desee hallar.
3. Mientras la cola no sea vacía:
3.1. Elimine el árbol que se encuentra en la cabeza de la cola. Llámese arb a este árbol.
3.2. Si el árbol arb no es vacío:
3.2.1. Visite la raíz del árbol arb.
3.2.2. Inserte en la cola el subárbol izquierdo del árbol arb.
3.2.3. Inserte en la cola el subárbol derecho del árbol arb.
Código 34: Método iterativo que halla el recorrido por niveles con complejidad temporal ,
donde es el peso del árbol.
public List<E> niveles() {
List<E> lista=new ArrayList<E>(); // Crear una lista nueva.
// Crear una nueva cola vacía para realizar el proceso:
Queue<VEDArbin<E>> cola=new LinkedList<VEDArbin<E>>();
cola.offer(this); // Añadir a la cola este árbol.
while (!cola.isEmpty()) { // Mientras la cola no sea vacía:
// Extraer la cabeza de la cola y guardarla en la variable 'actual':
VEDArbin<E> actual=cola.poll();
if (!actual.esVacio()) { // Si el árbol 'actual' no es vacío:
lista.add(actual.val); // Añadir a la lista la raíz del árbol 'actual'.
cola.offer(actual.izq); // Agregar a la cola el subárbol izquierdo de 'actual'.
cola.offer(actual.der); // Agregar a la cola el subárbol derecho de 'actual'.
}
}
return lista; // Retornar la lista.
}
¿Por qué funciona este algoritmo? El primer árbol que se añade a la cola es el árbol raíz, que
pertenece al nivel . Al sacar de la cola este árbol, se añaden a la cola sus subárboles, que
son precisamente los que pertenecen al nivel . Luego, para cada árbol del nivel , se saca de
la cabeza de la cola y se insertan en la cola sus subárboles, que son precisamente los que
pertenecen al nivel . Después, para cada árbol del nivel , se saca de la cabeza de la cola y
se insertan en la cola sus subárboles, que son precisamente los que pertenecen al nivel .
Siguiendo el proceso, descartando en cada paso los subárboles vacíos, se terminarían
visitando todos los nodos del árbol nivel por nivel.
ESTRUCTURAS DE DATOS 14
Tabla 36: Algoritmo para hallar manualmente el recorrido en inorden.
Ilustración representativa Algoritmo
Mentalmente, siga el rastro de la silueta del árbol
como muestra la ilustración. Cada vez que toque
un nodo por su parte inferior, añada su valor a
una lista. Los números dentro de las cajas rojas
muestran el orden en el que se van visitando los
elementos.
Recorrido en inorden del ejemplo:
Para poder reconstruir un árbol binario es necesario que todos sus elementos sean distintos,
porque de lo contrario, no se podría determinar de forma única la estructura del árbol.
ESTRUCTURAS DE DATOS 15
Gráfica 39: Cinco árboles binarios con elementos repetidos y con distinta forma, donde todos sus recorridos son iguales.
Además, es necesario tener el recorrido en inorden. El siguiente ejemplo muestra dos árboles
que tienen los mismos recorridos en preorden, en postorden y por niveles, pero diferente
recorrido en inorden:
Tabla 40: Dos árboles binarios tales que todos sus recorridos son iguales, excepto el inorden.
Recorrido
Árbol binario
Preorden Inorden Postorden Niveles
ESTRUCTURAS DE DATOS 16
2.1. Sea n el número de elementos del inorden, que coincide con el número de elementos
que tendrá el árbol que vamos a reconstruir.
2.2. Sea nuevoVal el primer elemento del recorrido en preorden, que es precisamente la raíz
del árbol.
2.3. Busque el valor nuevoVal en el inorden (sabemos que no aparece más de una vez porque
el árbol no tiene elementos repetidos). Sea pos la posición donde se encontró nuevoVal en el
inorden.
2.4. Aislamos el inorden del subárbol izquierdo, que es la sublista del inorden que va de la
posición 0 a la posición pos-1. Así mismo, aislamos el preorden del subárbol izquierdo, que es
la sublista del preorden que va de la posición 1 a la posición pos.
2.5. Llamamos recursivamente al algoritmo para reconstruir el subárbol izquierdo, según el
inorden y el preorden que aislamos en el paso anterior. Sea nuevoIzq el subárbol
reconstruido.
2.6. Aislamos el inorden del subárbol derecho, que es la sublista del inorden que va de la
posición pos+1 a la posición n-1. Así mismo, aislamos el preorden del subárbol derecho, que
es la sublista del preorden que va de la posición pos+1 a la posición n-1.
2.7. Llamamos recursivamente al algoritmo para reconstruir el subárbol derecho, según el
inorden y el preorden que aislamos en el paso anterior. Sea nuevoDer el subárbol
reconstruido.
2.8. Retorne un nuevo árbol binario cuya raíz sea nuevoVal, cuyo subárbol izquierdo sea
nuevoIzq y cuyo subárbol derecho sea nuevoDer.
Gráfica 41: Diagrama para guiar la reconstrucción de un árbol binario dado su recorrido en inorden y su recorrido en
preorden.
pos+1
pos-1
pos
n-3
n-2
n-1
0
pos
n-3
n-2
n-1
0
Tabla 42: Reconstrucción del árbol binario con inorden y con preorden .
Inorden Preorden Árbol Operación
La raíz es porque es el primer elemento del
preorden. En el inorden, a la izquierda del hay
dos elementos, y a la derecha hay cuatro. Por lo
tanto, se deduce que el subárbol izquierdo tiene
dos nodos y que el subárbol derecho tiene
cuatro nodos. Finalmente, aislamos tanto el
subárbol izquierdo como el subárbol derecho en
cada uno de los dos recorridos.
ESTRUCTURAS DE DATOS 17
Sabemos que el subárbol izquierdo tiene
inorden y preorden y que el
subárbol derecho tiene inorden y
preorden . De la misma forma,
reconstruimos ambos subárboles.
Sabemos que el subárbol izquierdo del nodo
tiene inorden y preorden . Con el
mismo procedimiento reconstruimos este árbol.
El siguiente algoritmo en Java reconstruye un árbol binario sin elementos repetidos a partir
de su inorden y de su preorden, con complejidad temporal .
Código 43: Rutina que reconstruye un árbol binario dado su inorden y su preorden.
public static <T> VEDArbin<T> reconstruirArbol(List<T> pInorden, List<T> pPreorden) {
if (pInorden.isEmpty()) { // Si el recorrido en inorden es vacío:
return new VEDArbin<T>(); // Retornar el árbol vacío.
}
else { // Si el recorrido en inorden no es vacío:
// Guardar en una variable el número de nodos que tendría el árbol a reconstruir:
int n=pInorden.size();
// Guardar en una variable la raíz del árbol, que está al principio del preorden:
T nuevoVal=pPreorden.get(0);
// Buscar la posición en la que aparece la raíz dentro del inorden:
int pos=pInorden.indexOf(nuevoVal);
// Extraer el inorden del subárbol izquierdo:
List<T> inordenIzq=pInorden.subList(0,pos);
// Extraer el preorden del subárbol izquierdo:
List<T> preordenIzq=pPreorden.subList(1,pos+1);
// Reconstruir recursivamente el subárbol izquierdo:
VEDArbin<T> nuevoIzq=VEDArbin.reconstruirArbol(inordenIzq,preordenIzq);
// Extraer el inorden del subárbol derecho:
List<T> inordenDer=pInorden.subList(pos+1,n);
// Extraer el preorden del subárbol derecho:
List<T> preordenDer=pPreorden.subList(pos+1,n);
// Reconstruir recursivamente el subárbol derecho:
VEDArbin<T> nuevoDer=VEDArbin.reconstruirArbol(inordenDer,preordenDer);
// Retornar el nuevo árbol reconstruido:
return new VEDArbin<T>(nuevoVal,nuevoIzq,nuevoDer);
}
}
Tabla 44: Ejemplos que ilustran cómo reconstruir árboles binarios usando la rutina descrita,
y cómo transformarlos en texto e imagen.
Programa Imagen exportada
List<Integer> in=Arrays.asList(); // Inorden
List<Integer> pre=Arrays.asList(); // Preorden
ESTRUCTURAS DE DATOS 18
VEDArbin<Integer> arbol=VEDArbin.reconstruirArbol(in,pre);
arbol.exportarComoImagen("ejemploReconstruccion01.png");
List<Integer> in=Arrays.asList(23,89,98,10); // Inorden
List<Integer> pre=Arrays.asList(98,23,89,10); // Preorden
VEDArbin<Integer> arbol=VEDArbin.reconstruirArbol(in,pre);
arbol.exportarComoImagen("ejemploReconstruccion02.png");
List<String> in=Arrays.asList("FÉ","LUZ","SOL"); // Inorden
List<String> pre=Arrays.asList("SOL","FÉ","LUZ"); // Preorden
VEDArbin<String> arbol=VEDArbin.reconstruirArbol(in,pre);
arbol.exportarComoImagen("ejemploReconstruccion03.png");
EN RESUMEN
Un árbol binario es una estructura de datos recursiva que está compuesta por un valor, llamado raíz,
y por dos árboles, llamados subárbol izquierdo y subárbol derecho.
Una hoja es un nodo sin hijos. Un nodo interno es un nodo que no es una hoja.
Una rama es un camino que va de la raíz a una hoja.
El peso ( ) de un árbol binario es el número de nodos que tiene. La altura ( ) de un árbol binario es
uno más la longitud de la rama más larga. Tanto el peso como la altura del árbol vacío se definen
como cero.
El recorrido en preorden visita primero la raíz del árbol, luego recorre el subárbol izquierdo en
preorden, y después recorre el subárbol derecho en preorden.
El recorrido en inorden recorre el subárbol izquierdo en inorden, luego visita la raíz del árbol, y
después recorre el subárbol derecho en inorden.
El recorrido en postorden recorre el subárbol izquierdo en postorden, luego recorre el subárbol
derecho en postorden, y después visita la raíz del árbol.
El recorrido por niveles visita los nodos nivel por nivel, desde el nivel hasta el nivel , donde
cada nivel se recorre de izquierda a derecha.
Para poder reconstruir un árbol binario sin ambigüedad, se requiere: 1. que el árbol no tenga
elementos repetidos, y 2. contar con el recorrido en inorden y con algún otro recorrido, ya sea en
preorden, en postorden o por niveles.
ESTRUCTURAS DE DATOS 19