BSTs en Java (parte 2)

Segunda parte de este ejemplo de árbol binario de búsqueda en Java en el que implementamos operaciones para obtener propiedades y recorrer el árbol en preorden, inorden y postorden.

Cuando trabajamos con árboles binarios de búsqueda en Java, lo primero que solemos hacer es comprobar si el árbol está vacío o si es una hoja. Un árbol vacío no tiene elementos, por lo que no puede ser considerado hoja. Sin embargo, cuando insertamos el primer elemento, el árbol deja de estar vacío y ese único nodo es una hoja, ya que no tiene hijos. Si añadimos un segundo elemento, el árbol ya no es hoja porque tiene más de un nodo. Por defecto, los elementos mayores suelen insertarse en el subárbol derecho.

Es importante manejar los duplicados con cuidado. Podemos decidir que al intentar insertar un elemento que ya existe en el árbol se lance una excepción, por ejemplo, un RuntimeException con un mensaje que indique que se está intentando insertar un elemento duplicado. Esto nos ayuda a mantener la integridad del árbol y evitar inconsistencias.

Para buscar elementos en el árbol, podemos implementar un método existe que devuelva true si el elemento está presente y false en caso contrario. La lógica es sencilla: primero comprobamos si el árbol está vacío; si lo está, el elemento no puede estar. Luego, comparamos el identificador del elemento buscado con el del nodo actual. Si coinciden, hemos encontrado el elemento. Si el id buscado es menor, seguimos buscando en el subárbol izquierdo; si es mayor, en el derecho.

Además, podemos implementar un método obtener que devuelva el propio objeto almacenado en el árbol si lo encuentra, o null si no está presente. Para evitar errores, es recomendable comprobar primero si el elemento existe antes de intentar obtenerlo. También debemos asegurarnos de que al recorrer los subárboles izquierdo y derecho comprobamos que no sean null antes de hacer llamadas recursivas, para evitar excepciones.

En cuanto a los recorridos del árbol, existen tres formas clásicas: preorden, inorden y postorden. En el recorrido preorden, procesamos primero la raíz, luego el subárbol izquierdo y finalmente el derecho. En el inorden, procesamos primero el subárbol izquierdo, luego la raíz y después el derecho. En el postorden, procesamos primero el subárbol izquierdo, luego el derecho y finalmente la raíz.

Para imprimir el árbol de forma clara y visual, podemos implementar métodos recursivos que añadan un prefijo o margen que aumente a medida que descendemos por los niveles del árbol. Por ejemplo, podemos pasar una cadena vacía inicialmente y, en cada llamada recursiva, añadir dos espacios más al prefijo. Así, al imprimir cada nodo, el margen nos ayuda a visualizar la estructura jerárquica del árbol.

Cuando insertamos varios elementos en el árbol, podemos usar las características de Java 8 para simplificar el proceso. Por ejemplo, podemos tomar una lista de elementos y usar un método como forEach para insertarlos todos en el árbol de forma concisa.

Al imprimir el árbol en preorden con este sistema de prefijos, veremos primero la raíz, luego el hijo izquierdo con un margen mayor, y después el derecho con un margen similar. Esto nos permite entender fácilmente la estructura y la relación entre los nodos.

Para ilustrar cómo implementar estos recorridos con el prefijo que indica la profundidad, podemos definir métodos privados que reciban el prefijo y lo vayan incrementando en cada llamada recursiva. Por ejemplo, para el recorrido preorden:

private void preordenImpl(String prefijo) {
    if (valor != null) {
        System.out.println(prefijo + valor);
        if (izquierdo != null) {
            izquierdo.preordenImpl(prefijo + "  ");
        }
        if (derecho != null) {
            derecho.preordenImpl(prefijo + "  ");
        }
    }
}

public void preorden() {
    preordenImpl("");
}

De forma similar, para el recorrido inorden:

private void inordenImpl(String prefijo) {
    if (valor != null) {
        if (izquierdo != null) {
            izquierdo.inordenImpl(prefijo + "  ");
        }
        System.out.println(prefijo + valor);
        if (derecho != null) {
            derecho.inordenImpl(prefijo + "  ");
        }
    }
}

public void inorden() {
    inordenImpl("");
}

Y para el postorden:

private void postordenImpl(String prefijo) {
    if (valor != null) {
        if (izquierdo != null) {
            izquierdo.postordenImpl(prefijo + "  ");
        }
        if (derecho != null) {
            derecho.postordenImpl(prefijo + "  ");
        }
        System.out.println(prefijo + valor);
    }
}

public void postorden() {
    postordenImpl("");
}

Con estas implementaciones, podemos visualizar el árbol de manera ordenada y clara, entendiendo la jerarquía y el orden en que se procesan los nodos según el tipo de recorrido que elijamos. Esto facilita tanto la depuración como la comprensión de la estructura del árbol binario de búsqueda.

Lista de reproducción
  1. 1
    Qué son las estructuras de datos
    3 minutos
  2. 2
    Listas enlazadas: Teoría
    12 minutos
  3. 3
    Listas enlazadas en C
    18 minutos
  4. 4
    Listas enlazadas en Java
    17 minutos
  5. 5
    Colas: teoría
    6 minutos
  6. 6
    Colas en C
    12 minutos
  7. 7
    Colas en Java
    10 minutos
  8. 8
    Pilas: teoría
    7 minutos
  9. 9
    Pilas en C
    11 minutos
  10. 10
    Pilas en Java
    10 minutos
  11. 11
    Introducción a los árboles
    11 minutos
  12. 12
    Árboles binarios
    9 minutos
  13. 13
    Árboles binarios de búsqueda (parte 1)
    10 minutos
  14. 14
    Árboles de búsqueda binaria (parte 2)
    8 minutos
  15. 15
    BSTs en C (parte 1)
    13 minutos
  16. 16
    BSTs en C (parte 2)
    8 minutos
  17. 17
    BSTs en C (y parte 3)
    18 minutos
  18. 18
    BSTs en Java (parte 1)
    9 minutos
  19. 19
    BSTs en Java (parte 2)
    11 minutos
  20. 20
    BSTs en Java (parte 3)
    10 minutos
  21. 21
    Árbol desde preorden e inorden
    8 minutos
  22. 22
    Árbol desde inorden y postorden
    8 minutos
  23. 23
    Árboles k-arios
    6 minutos
  24. 24
    Árboles B (parte 1)
    11 minutos
  25. 25
    Árboles B (parte 2)
    20 minutos
  26. 26
    Árboles B (parte 3)
    39 minutos