Mostrando las entradas con la etiqueta Recorrido de árboles. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Recorrido de árboles. Mostrar todas las entradas

12 de junio de 2017

Árboles binarios balanceados (AVL).

   Existen diferentes tipos y variaciones de los árboles binarios, y una de las más importantes es la de los árboles binarios balanceados, árboles binarios de búsqueda balanceados, o simplemente, árboles AVL.

Definición y conceptos.
   Un árbol binario balanceado (también conocidos simplemente como árboles AVL en honor a sus creadores Adelson-Velski y Landis) es un árbol binario de búsqueda (ABB) en el que las alturas de los dos subárboles de cada nodo difieren a lo más en 1.

   El balance de un nodo en un árbol binario en general y de un árbol AVL en particular, se define como la altura de su subárbol izquierdo menos la altura de su subárbol derecho:

| altura(arbolIzquierdo) - altura(arbolDerecho) | < 2

   También existe la correspondiente definición simétrica: la altura de su subárbol derecho menos la altura de su subárbol izquierdo; pero en este blog se adoptará la primera. Por convención, la altura de un árbol AVL nulo o vacío se define como -1.

   Durante el proceso de inserción o eliminación puede ocurrir un desbalance, es decir, que el valor absoluto de la altura de alguno de los nodos del árbol AVL sea mayor que 1.

   En caso de existir desbalance en alguno de los nodos, es decir, una condición que incumpla lo establecido por la expresión anterior, se tiene que rebalancear el árbol para que éste siga siendo un árbol AVL válido.

   En este sentido, existen cuatro casos que corrigen el balanceo de un árbol AVL:
  1. Caso 1: rotación simple derecha.
  2. Caso 2: rotación simple izquierda.
  3. Caso 3: rotación doble izquierda derecha.
  4. Caso 4: rotación doble derecha izquierda.
   A continuación se describen dos de estos cuatro casos, debido a que los otros dos son simétricos y pueden derivarse fácilmente a partir de los que se presentan.

Rotación simple.
   El primer caso de rebalanceo, la rotación derecha también conocida como rotación simple, se ilustra en la siguiente figura:

Caso 1: rotación derecha (adaptada de Wirth).
 
    La figura (a) muestra hasta antes de la inserción del elemento representado por el cuadrado rojo (cuadrado más obscuro), un árbol AVL balanceado. El balance puede determinarse gráficamente por los niveles representados por líneas horizontales punteadas: el balance para los nodos A y B es 0 y 1 respectivamente. Al insertar el elemento representado por el cuadrado rojo (cuadrado más obscuro), se presenta un desbalance sobre el nodo B: ahora el balance para los nodos A y B es 1 y 2 respectivamente.

   Por otro lado, la figura (b) muestra la solución al desbalanceo descrito en el párrafo anterior. Para visualizarlo mejor, imagine que en la figura (a), en el nodo representado por B existe una polea fija, de tal forma que al "jalar" z hacia abajo, el subárbol izquierdo de B representado por A sube, mientras que B baja convirtiéndose en el subárbol derecho de A. Note cómo y pasa de ser subárbol derecho de A, a ser subárbol izquierdo de B.

   Para el caso de la rotación izquierda el proceso es análogo pero de manera simétrica, al de la rotación derecha descrita en esta sección.

   Ejemplo.
   Considere el árbol AVL (asegúrese de que en efecto sea un árbol AVL y determine que el balance de cada uno de los nodos que se presenta es correcto) que aparece en la siguiente figura en (a):


Ejemplo de la aplicación de la rotación simple.
 
    La rotación simple derecha se presenta al insertar los elementos 1 o 3, los cuales se resaltan y presentan en la figura (b).

   El nodo desbalanceado es el que contiene al elemento 8 (¿Por qué?). La aplicación del Caso 1 de rotación dará como resultado el árbol AVL que aparece en la figura (c) dependiendo del elemento (1 o 3) que se haya insertado, de tal forma que la rotación simple derecha se realiza sobre el nodo que contiene al elemento 8 de la figura (b).

   Observe cómo la aplicación de la rotación simple corrige el balance general del árbol, de tal forma que el balance obtenido es casi perfecto.

   Antes de continuar, asegúrese de comprender el proceso de rebalanceo aplicado a la figura anterior, así como de determinar por su propia cuenta, el balance de cada uno de los nodos para los tres incisos.

Rotación doble.
   El caso de rebalanceo que implica una rotación doble es un proceso un poco más elaborado que el de la rotación simple, ya que como su nombre lo indica, implica dos rotaciones. La rotación doble izquierda derecha se muestran en la siguiente figura:

Caso3: rotación doble izquierda derecha (adaptada de Wirth).
 
    Ante una situación como la que se presenta en la figura (a) la solución está dada por la figura (c). Ahora bien, existe un paso intermedio entre éstas, mismo que está representado por la figura (b) y es el que se explicará a continuación:
  • La figura (a) muestra, hasta antes de la inserción del elemento representado por el cuadrado rojo (cuadrado más obscuro), un árbol AVL balanceado. El balance puede determinarse gráficamente por los niveles representados por líneas horizontales punteadas: el balance para los nodos A, B y C es 0, 0 y 1 respectivamente. Al insertar cualquiera de los elementos representados por el cuadrado rojo (cuadrado más obscuro), se presenta un desbalance sobre el nodo C: ahora el balance para los nodos A, B y C es -1, (1 o -1 según sea el elemento insertado) y 2 respectivamente.
  • Aunque C es el nodo desbalanceado, observe que el balance no se corrige si se realiza una rotación derecha sobre C (asegúrese de comprobarlo). Por otro lado, note los signos de los balances generados por la inserción del elemento que provoca el desbalance.
  • En base a lo anterior, la figura (b) muestra una rotación izquierda sobre A aunque el nodo A no está desbalanceado. Note que el balance no se ha corregido todavía, ya que el balance de A es 0 o 1, el de B es 2 o 1, y el de C 2.
  • Ahora bien, partiendo de la figura (b), una nueva rotación derecha sobre C generará el árbol de la figura (c) mejorando significativamente el balance general de la mayoría de los nodos.
    Asegúrese de comprender la doble rotación izquierda derecha explicada hasta aquí antes de continuar.

   El caso de la rotación doble derecha izquierda es simétricamente análogo o lo descrito con anterioridad.

   Ejemplo.
   Para ilustrar la rotación doble, considere el árbol AVL que aparece en la siguiente figura en (a). Una vez más y antes de continuar, compruebe que dicho árbol es un árbol AVL y que los balances propuestos son correctos.

Ejemplo de aplicación de la rotación doble.

   La rotación doble se presenta al insertar cualquiera de los elementos 5 o 7 (figura (b)).

   La aplicación de la rotación doble dará como resultado el árbol AVL que aparece en la figura (c) dependiendo del nodo que se haya insertado. Se deja como ejercicio para el lector generar el paso intermedio y comparar su resultado con el de la figura (c). El paso intermedio consiste en hacer una rotación izquierda sobre 4 en la figura (b), y posteriormente una rotación derecha sobre 8; estas dos rotaciones deberán generar la figura (c). Una vez más observe los signos de los balances en la rotación simple y en la doble; y asegúrese de comprender los procesos de balanceo aplicados en los ejemplos.

Consideraciones finales.
   Los árboles binarios tienen muchas y muy variadas aplicaciones. En este blog sólo se ha presentado una introducción tanto a los conceptos, como a algunos de los árboles binarios más comunes, pero es importante que el lector esté consciente de que los árboles binarios estudiados en esta sección no son los únicos tipos de árboles binarios.

   Otro tipos de árboles binarios son, por ejemplo:
  • Árbol perfectamente balanceado.
  • Árbol rojo negro.
  • Árbol AA.
  • Árbol biselado (splay).
   Se recomienda ampliamente al lector buscar información relacionada con al menos estos tipos de árboles binarios, con la finalidad de complementar y ampliar de mejor manera tanto sus conocimientos, como su visión de esta poderosa, versátil y útil estructura de datos.

29 de mayo de 2017

ABB (implementación).

   Esta entrada presenta la implementación de un ABB en base a dos enfoques respecto a la inserción de elementos:
  1. Enfoque recursivo.
  2. Enfoque iterativo.
   Para ambas implementaciones se utiliza la clase NodoABB definida en el Ejemplo NodoABB, por lo que será la primera clase que se describirá.

   La clase NodoABB define un nodo capaz de almacenar objetos genéricos. Cada nodo definido por la clase tiene la forma de cada uno de los nodos de la siguiente figura:

Árbol binario de búsqueda (ABB) conformado por objetos de la clase NodoABB.
 
    Observe además que cada objeto instanciado tendrá dos referencias a objetos como él, las cuales representarán referencias hacia el subárbol izquierdo (nodoIzquierdo) y hacia el subárbol derecho (nodoDerecho).

   Los detalles restantes deberían resultarle familiares al lector, ya que en esencia se refieren a un constructor y a los métodos de tipo set y get para cada uno de los atributos. Asegúrese de comprender el Ejemplo NodoABB en su totalidad antes de continuar.

Enfoque recursivo.
   Probablemente el enfoque más común para la implementación de un ABB debido a la naturaleza inherente a la definición de dicha estructura de datos, sea el enfoque basado en la recursividad.

   El Ejemplo ABBr muestra la definición de la clase ABBr, la cual es en esencia la implementación de la representación definida en el diagrama de clases UML presentado en la entrada ABB (representación y diseño).

   El estudio y la comprensión de la implementación de los métodos de recorrido para un árbol binario de búsqueda (líneas 34-68), se dejan como ejercicio para el lector.

   El método inserta (líneas 13-18), crea la raíz del árbol (línea 15) si el ABB está vacío (línea 14), i.e. no existe. En caso contrario, delega la responsabilidad de la inserción de elemento dentro de arbol al método privado recursivo insertaR (línea 17).

   Por su parte, la idea del método insertaR (líneas 21-32) es verificar la relación de orden de elemento respecto del dato almacenado en el nodo actual, y entonces:
  • Si elemento es menor (línea 22), debe ser insertado en el subárbol izquierdo.
  • Si el subárbol izquierdo está vacío o disponible (línea 23), se crea un nuevo nodo con elemento como dato y se asigna como hijo izquierdo (línea 24). Si no está vacío (línea 25), se recorre el subárbol izquierdo de manera recursiva (línea 26) para encontrar la posición apropiada para elemento dentro del subárbol.
  • Si elemento es mayor (línea 27), debe ser insertado en el subárbol derecho.
  • Si el subárbol derecho está vacío o disponible (línea 28), se crea un nuevo nodo con elemento como dato y se asigna como hijo derecho (línea 29). Si no está vacío (línea 30), se recorre el subárbol derecho de manera recursiva (línea 31) para encontrar la posición apropiada para elemento dentro del correspondiente subárbol.
   La clase de prueba para la clase ABBr del Ejemplo ABBr se muestra en el Ejemplo PruebaArbol.

   La clase PruebaArbol del Ejemplo PruebaArbol utiliza la clase Random del API para generar un número aleatorio (línea 14) dentro de un rango específico; el cual, además de presentarse en la salida estándar (línea 15), representa el valor a ser insertado dentro del árbol binario de búsqueda (línea 16).

   Finalmente, el Ejemplo PruebaArbol realiza los tres recorridos más convencionales definidos para un ABB (líneas 19-27). Es ampliamente recomendable que el lector realice varias ejecuciones de la clase PruebaArbol y corrobore la salida con inserciones y recorridos realizados a papel y lápiz.

Una posible salida de los Ejemplos PruebaArbol y Prueba ABB.
 
    Una posible salida para el Ejemplo PruebaArbol se muestra en la figura anterior.

Enfoque iterativo.
   Un enfoque alternativo para la implementación de la operación de inserción en un árbol binario de búsqueda, es utilizar un ciclo en lugar de recursividad.

   El enfoque propuesto es casi tan compacto como el recursivo pero mucho más eficiente. La implementación sin recursividad del ABB representado en el diagrama de clase de la entrada ABB (representación y diseño) se presenta en el Ejemplo ABB.

   Al igual que antes, el estudio y la comprensión de la implementación de los métodos de recorrido (líneas 34-68), se dejan como ejercicio para el lector.

   El método inserta (líneas 13-32), crea la raíz del árbol (línea 15) si el ABB está vacío (línea 14), i.e. no existe. En caso contrario, se genera una referencia alterna (línea 17) para recorrer el árbol (línea 18).

   Al igual que antes, la idea es verificar la relación de orden de elemento respecto del dato almacenado en el nodo actual, y entonces:
  • Si elemento es menor (línea 19), debe ser insertado en el subárbol izquierdo.
  • Si el subárbol izquierdo está vacío o disponible (línea 20), se crea un nuevo nodo con elemento como dato y se asigna como hijo izquierdo (línea 21). Si no está vacío (línea 22), se cambia la referencia del subárbol en cuestión (abb), y se recorre el subárbol izquierdo (línea 23) para encontrar la posición apropiada para elemento dentro del árbol.
  • Si elemento es mayor (línea 24), debe ser insertado en el subárbol derecho.
  • Si el subárbol derecho está vacío o disponible (línea 25), se crea un nuevo nodo con elemento como dato y se asigna como hijo derecho (línea 26). Si no está vacío (línea 27), se cambia la referencia del subárbol en cuestión (abb), y se recorre el subárbol derecho (línea 28) para encontrar la posición apropiada para elemento dentro del ABB.
  • Finalmente, si el elemento no fue menor ni mayor, entonces por tricotomía de los números no le queda otra más que ser igual, en cuyo caso no hay nada por hacer mas que terminar (líneas 29 y 30).
   La clase de prueba para la clase ABB del Ejemplo ABB se muestra en el Ejemplo PruebaABB.

   Al igual que antes, la clase PruebaABB del Ejemplo PruebaABB utiliza la clase Random del API para generar un número aleatorio (línea 14) dentro de un rango específico, el cual además de presentarse en la salida estándar (línea 15), representa el valor que será insertado dentro del árbol binario de búsqueda (línea 16).

   Finalmente, el Ejemplo PruebaABB también realiza los tres recorridos más convencionales definidos para un ABB (líneas 19-27). Una vez más, se recomienda ampliamente que el lector realice varias ejecuciones de la clase PruebaABB y corrobore la salida con inserciones y recorridos realizados a papel y lápiz.

26 de mayo de 2017

Ejercicios selectos (árboles binarios).

Representación de un ABB.
  1. Siguiendo las consideraciones descritas en el blog respecto a un ABB (entrada Árbol binario de búsqueda (ABB)), realice manualmente, es decir, en papel y lápiz, la inserción de la siguiente secuencia de elementos: 14, 15, 4, 9, 7, 18, 3, 5, 16, 4, 20, 17.
    1. Aplique el recorrido en pre orden al árbol resultante.
    2. Aplique el recorrido en orden al árbol resultante.
    3. Aplique el recorrido en post orden al árbol resultante.
    4. Aplique también el recorrido en pre orden inverso.
    5. Aplique el recorrido en orden inverso al árbol resultante.
    6. Aplique finalmente el recorrido en post orden inverso.
  2. Realice lo mismo que en el ejercicio anterior pero con la secuencia de números invertida, i.e.: 17, 20, 4, 16, 5, 3, 18, 7, 9, 4, 15, 14.
    1. Aplique el recorrido en pre orden al árbol resultante.
    2. Aplique el recorrido en orden al árbol resultante.
    3. Aplique el recorrido en post orden al árbol resultante.
    4. Aplique también el recorrido en pre orden inverso.
    5. Aplique el recorrido en orden inverso al árbol resultante.
    6. Aplique finalmente el recorrido en post orden inverso.
  3. Modifique el Ejemplo PruebaArbol para que permita leer números desde la entrada estándar. Corrobore con el programa y los recorridos obtenidos en los ejercicios anteriores, que el árbol que genera el programa es el mismo que generó en papel y lápiz.
  4. Basándose en el Ejemplo NodoABB, el Ejemplo ABBr, y el Ejemplo ABB, realice las modificaciones correspondientes en ambos tipos de implementación (recursiva e iterativa) para que, a través de métodos, proporcione solución a lo siguiente:
    1. Dadas dos referencias a dos nodos cualesquiera de un árbol binario, determine si r1 es padre de r2 (vea la figura que aparece al inicio de esta entrada).
    2. Dadas dos referencias a dos nodos cualesquiera de un árbol binario, determine si r2 es hijo de r1 (vea la figura que aparece al inicio de esta entrada).
    3. Dada una referencia a un nodo cualquiera de un árbol binario, determine si dicho nodo es o no un nodo hoja.
    4. Dadas dos referencias a dos nodos cualesquiera de un árbol binario, determine si r1 es ancestro de r2.
    5. Dadas dos referencias a dos nodos cualesquiera de un árbol binario, determine si r2 es descendiente de r1.
    6. Dada una referencia a un nodo cualquiera de un árbol binario, determine su nivel.
    7. Determinar la altura o profundidad de un árbol binario.
    8. Determinar si un árbol binario es o no un árbol estrictamente binario.
    9. Determinar si un árbol binario es o no un árbol binario completo de profundidad p.
    10. La implementación de las operaciones complementarias:
      1. obtenPadre: regresa una referencia al padre de nd.
      2. obtenHermano: regresa una referencia al hermano de nd.
      3. esIzquierdo: regresa true si nd es un hijo izquierdo de algún otro nodo en el árbol binario, y false en caso contrario.
      4. esDerecho: regresa true si nd es un hijo derecho de algún otro nodo en el árbol binario, y false en caso contrario.
      5. Donde nd es una referencia a un nodo cualquiera de un árbol binario.
    11. Determinar el número de nodos de un árbol binario.
    12. La suma (se asume que el árbol binario almacena números) de todos los nodos del árbol binario.
  5. Modifique el Ejemplo PruebaArbol para que almacene otro tipo de objetos además de los de la clase Integer. Pruebe con al menos las siguientes clases:
    1. Float.
    2. String.
    3. Persona (del Ejemplo Persona).
    4. Cientifico (del Ejemplo Cientifico).
  6. Realice lo mismo que se pide en el ejercicio anterior, pero para el Ejemplo PruebaABB.
  7. Modifique el Ejemplo PruebaABB para que:
    1. En lugar de insertar números aleatorios en el árbol binario de búsqueda, solicite al usuario un número de datos n. Posteriormente deberá leer de la entrada estándar cada uno de los n datos, mismos que serán insertados en el ABB correspondiente.
    2. Realice las comprobaciones de los recorridos y árboles generados manualmente. Un recorrido en preorden o postorden le hará saber si el árbol generado es correcto, tome en consideración que un recorrido en orden no le arrojará información útil al respecto.
    3. Implemente los recorridos inversos descritos en la entrada (Árboles binarios (recorridos)). Nota: respecto a los recorridos inversos, resultaría sumamente conveniente que, previo a su implementación, realizara el diagrama de clases UML correspondiente basándose en el presentado en la entrada ABB (representación y diseño).
  8. Con base en las consideraciones planteadas en el blog respecto a la eliminación de un ABB y al diagrama de clases UML presentado en la entrada ABB (eliminación), implemente la eliminación de elementos para un árbol binario de búsqueda, así como las modificaciones correspondientes mostradas en dicho diagrama.
  9. Dada la siguiente secuencia de números: 4, 5, 7, 2, 1, 3, 6, genere en papel y lápiz su correspondiente ABB. Se deberá ilustrar paso a paso el proceso de inserción y realizar la comprobación de cada árbol con el programa generado en el Ejercicio 7.
  10. Realice lo mismo que en el ejercicio anterior pero con la secuencia de números invertida, i.e.: 6, 3, 1, 2, 7, 5, 4.
  11. Dada la siguiente secuencia de números: 4, 5, 7, 2, 1, 3, 6, genere en papel y lápiz su correspondiente árbol AVL. Se deberá ilustrar paso a paso el proceso de inserción y rebalanceo.
  12. Realice lo mismo que en el ejercicio anterior pero con la secuencia de números invertida, i.e.: 6, 3, 1, 2, 7, 5, 4.
  13. Dada la siguiente secuencia de números: 8, 9, 11, 15, 19, 20, 21, 7, 3, 2, 1, 5, 6, 4, 13, 14, 10, 12, 17, 16, 18, generar:
    1. El correspondiente ABB.
    2. El correspondiente árbol AVL.
    3. El correspondiente ABB pero con la secuencia de números invertida.
    4. El correspondiente árbol AVL pero con la secuencia de números invertida.
    5. En cada caso se deberá ilustrar paso a paso en cada uno de los árboles generados, el correspondiente proceso de inserción.
  14. Respecto al ejercicio anterior:
    1. ¿Qué conjeturas puede obtener?
    2. ¿En qué tipo de árbol se genera el árbol de altura mínima?
    3. ¿Cuáles serían las ventajas y desventajas de uno y otro esquema de representación de árbol y por qué?
  15. Considere la figura (a) que aparece al final de esta entrada de ejercicios, misma que representa un árbol AVL. Utilizando papel y lápiz:
    1. Elimine la siguiente secuencia de elementos: 4, 8, 6, 5, 2, 1, 7.
    2. Deberá ilustrar paso a paso:
      1. Los balances de cada uno de los nodos.
      2. La identificación del nodo a eliminar y el proceso de rebalanceo a aplicar en caso de ser necesario.
      3. El correspondiente árbol AVL.
    3. La solución final al ejercicio se presenta en la figura (b).
  16. Genere el diagrama de clases UML que represente el diseño de un árbol AVL en base a lo expuesto en el blog. Puede basarse en el diagrama de la entrada ABB (representación y diseño). La idea de este ejercicio es que su diseño derive en una implementación.
  17. Realice la implementación de un árbol AVL. Tome en consideración que, además de mantener los elementos ordenados como en un ABB, en cada inserción deberá verificar el balance de los nodos, y que en caso de ser necesario, deberá aplicar los mecanismos de rebalanceo descritos en el blog para asegurar que el árbol generado es siempre un árbol AVL.
  18. En la entrada Árboles binarios balanceados (AVL) se discuten los aspectos de los árboles AVL relacionados con el rebalanceo después de la inserción. Sin embargo, ¿qué pasa con la eliminación de elementos? Apoyándose en el blog y en el ejercicio anterior, analice y resuelva los aspectos implicados en la eliminación de nodos en un árbol AVL, e implemente una operación que permita realizar la eliminación de un elemento. Asegúrese de mantener siempre un árbol AVL.
(a) Árbol AVL inicial para la eliminación (adaptada del libro Algoritmos y Estructuras de Datos de Niklaus Wirth).
(b) Árbol AVL final después del proceso de eliminación.

25 de mayo de 2017

Árbol binario de búsqueda (ABB).

   Un árbol binario es una estructura de datos sumamente útil en muchos aspectos, en particular, cuando deben tomarse decisiones en dos sentidos en cada punto de un proceso determinado.

   Con base en lo anterior, suponga que por alguna razón se desea encontrar todos los duplicados de una secuencia de números. Para ello, considere lo siguiente:
  1. El primer número de la secuencia se coloca en un nodo que se ha establecido como la raíz de un árbol binario, cuyos subárboles izquierdo y derecho estarán inicialmente vacíos.
  2. Cada número sucesivo en la secuencia se compara con el número que se encuentra en la raíz del árbol binario. En este momento, se tienen tres casos a considerar:
    1. Si coincide, se tiene un duplicado.
    2. Si es menor, se examina el subárbol izquierdo.
    3. Si es mayor, se examina el subárbol derecho.
  3. Si alguno de los subárboles esta vacío, el número no es un duplicado y se coloca en un nodo nuevo en dicha posición del árbol binario.
  4. Si el subárbol correspondiente no está vacío, se compara el número con la raíz del subárbol en cuestión, y se repite todo el proceso nuevamente con dicho subárbol.
   Un árbol binario de búsqueda (ABB) es un árbol binario que no tiene valores duplicados en los nodos, y además, tiene las siguientes características:
  1. Los valores en cualquier subárbol izquierdo son menores que el valor en su nodo padre.
  2. Los valores en cualquier subárbol derecho son mayores que el valor en su nodo padre.
   Tome en cuenta que un ABB es un árbol binario, pero un árbol binario no es necesariamente un ABB. En este sentido, todo lo que se ha dicho y definido para árboles binarios, es aplicable también a los árboles binarios de búsqueda.

Operaciones primitivas.
   Respecto a las operaciones primitivas, se definen cuatro operaciones primitivas para un ABB:
  • inserta: inserta un nuevo nodo al árbol binario de búsqueda. La inserción se realiza de manera ordenada respecto del elemento a insertar, por lo que debe existir una relación de orden definida para el conjunto de datos al que pertenece dicho elemento.
   En resumen, la operación inserta de manera ordenada a elemento en el ABB cuando el objeto abb recibe el mensaje correspondiente, es decir: abb.inserta(elemento).
  • recorre en preorden: recorre el ABB no vacío en orden previo, de tal forma que cuando el objeto abb recibe el mensaje: abb.recorrePreorden( ) se imprime en la salida estándar el recorrido en orden previo de abb.
  • recorrido en orden: recorre el árbol binario de búsqueda no vacío en orden, de tal forma que cuando el objeto abb recibe el mensaje: abb.recorreEnorden( ) se imprime en la salida estándar el recorrido en orden de abb.
   Note cómo un recorrido en orden, como su nombre lo indica, imprime en la salida estándar los elementos almacenados en el árbol ordenados de manera ascendente.
  • recorrido en postorden: recorre el ABB no vacío en orden posterior, de tal forma que cuando el objeto abb recibe el mensaje: abb.recorrePostorden( ) se imprime en la salida estándar el recorrido en orden posterior de abb.
   Para el caso de un árbol binario de búsqueda, también serían deseables otras operaciones, como aquellas que se definieron para los árboles binarios: primitivas, operaciones adicionales que podrían ser útiles y recorridos inversos por ejemplo (vea las entradas Árboles binarios (operaciones primitivas) y Árboles binarios (recorridos)).

   En este sentido, es importante resaltar que siempre que una operación no viole la relación de orden intrínseca a los ABB, es factible de ser implementada y que la decisión final respecto a su implementación estará en directa función de si ésta tiene o no sentido en la aplicación que se esté desarrollando.

24 de mayo de 2017

Árboles binarios (recorridos).

   Una operación muy común en un árbol binario es la de recorrer todo el árbol en un orden específico pero ¿Cuál sería el orden natural de recorrido de un árbol binario? Piense por un momento en ello.

   A la operación de recorrer un árbol binario de una forma específica y de enumerar o visitar sus nodos, se le conoce como visitar el árbol, es decir, procesar el valor o dato de cada uno de los nodos para realizar algo con él.

   En general, se definen tres métodos de recorrido sobre un árbol binario, y para ello, se deberán tomar en cuenta las siguientes consideraciones:
  1. No se necesita hacer nada para un árbol binario vacío.
  2. Todos los métodos se definen recursivamente.
  3. Siempre se recorren la raíz y los subárboles izquierdo y derecho, la diferencia radica en el orden en que se visitan.
   Para recorrer un árbol binario no vacío en orden previo (orden de primera profundidad), se ejecutan tres operaciones:
  1. Visitar la raíz.
  2. Recorrer el subárbol izquierdo en orden previo.
  3. Recorrer el subárbol derecho en orden previo.
   Ahora bien, para recorrer un árbol binario no vacío en orden (orden simétrico), se ejecutan tres operaciones:
  1. Recorrer el subárbol izquierdo en orden.
  2. Visitar la raíz.
  3. Recorrer el subárbol derecho en orden.
   Finalmente, para recorrer un árbol binario no vacío en orden posterior, se ejecutan tres operaciones:
  1. Recorrer el subárbol izquierdo en orden posterior.
  2. Recorrer el subárbol derecho en orden posterior.
  3. Visitar la raíz.
   Tome en consideración que los tres recorridos anteriormente descritos son únicamente tres posibilidades de seis recorridos distintos que es posible realizar sobre un árbol binario; sin embargo, son los recorridos más comunes.

   Los otros tres recorridos posibles se describen a continuación, y a falta de un mejor nombre, se les denominará recorridos inversos.

Para recorrer un árbol binario no vacío en orden previo inverso, se ejecutan tres operaciones:
  1. Visitar la raíz.
  2. Recorrer el subárbol derecho en orden previo inverso.
  3. Recorrer el subárbol izquierdo en orden previo inverso.
   Por otro lado, para recorrer un árbol binario no vacío en orden inverso, se ejecutan tres operaciones:
  1. Recorrer el subárbol derecho en orden inverso.
  2. Visitar la raíz.
  3. Recorrer el subárbol izquierdo en orden inverso.
   Finalmente, para recorrer un árbol binario no vacío en orden posterior inverso, se ejecutan tres operaciones:
  1. Recorrer el subárbol derecho en orden posterior inverso.
  2. Recorrer el subárbol izquierdo en orden posterior inverso.
  3. Visitar la raíz.