¿Cuáles son las aplicaciones de los árboles binarios?

323

Me pregunto cuáles son las aplicaciones particulares de los árboles binarios. ¿Podrías dar algunos ejemplos reales?

Jichao
fuente

Respuestas:

425

Discutir sobre el rendimiento de los árboles binarios no tiene sentido: no son una estructura de datos, sino una familia de estructuras de datos, todas con diferentes características de rendimiento. Si bien es cierto que los árboles binarios desequilibrados tienen un rendimiento mucho peor que los árboles binarios autoequilibrados para la búsqueda, existen muchos árboles binarios (como los intentos binarios) para los cuales "equilibrar" no tiene sentido.

Aplicaciones de árboles binarios.

  • Árbol de búsqueda binaria : se usa en muchas aplicaciones de búsqueda donde los datos entran y salen constantemente, como los objetos mapy seten las bibliotecas de muchos idiomas.
  • Partición de espacio binario : se utiliza en casi todos los videojuegos en 3D para determinar qué objetos deben representarse.
  • Pruebas binarias : se utilizan en casi todos los enrutadores de gran ancho de banda para almacenar tablas de enrutadores.
  • Hash Trees : se utiliza en programas p2p y firmas de imágenes especializadas en las que se debe verificar un hash, pero el archivo completo no está disponible.
  • Montones : se utilizan para implementar colas de prioridad eficientes, que a su vez se utilizan para programar procesos en muchos sistemas operativos, calidad de servicio en enrutadores y A * (algoritmo de búsqueda de ruta utilizado en aplicaciones de IA, incluida la robótica y los videojuegos) . También se usa en heap-sort.
  • Huffman Coding Tree ( Chip Uni ): utilizado en algoritmos de compresión, como los utilizados por los formatos de archivo .jpeg y .mp3.
  • Árboles GGM : se utilizan en aplicaciones criptográficas para generar un árbol de números pseudoaleatorios.
  • Árbol de sintaxis : construido por compiladores y (implícitamente) calculadoras para analizar expresiones.
  • Treap : estructura de datos aleatorios utilizada en redes inalámbricas y asignación de memoria.
  • T-tree : aunque la mayoría de las bases de datos utilizan algún tipo de B-tree para almacenar datos en el disco, las bases de datos que mantienen todos (la mayoría) de sus datos en la memoria a menudo usan T-trees para hacerlo.

La razón por la que los árboles binarios se usan con más frecuencia que los árboles n-arios para la búsqueda es que los árboles n-arios son más complejos, pero generalmente no ofrecen una ventaja de velocidad real.

En un árbol binario (equilibrado) con mnodos, pasar de un nivel al siguiente requiere una comparación, y hay log_2(m)niveles, para un total de log_2(m)comparaciones.

Por el contrario, un árbol n-ary requerirá log_2(n)comparaciones (usando una búsqueda binaria) para pasar al siguiente nivel. Como hay log_n(m)niveles totales, la búsqueda requerirá log_2(n)*log_n(m)= log_2(m)comparaciones totales. Entonces, aunque los árboles n-arios son más complejos, no proporcionan ninguna ventaja en términos de comparaciones totales necesarias.

(Sin embargo, los árboles n-arios siguen siendo útiles en situaciones de nicho. Los ejemplos que vienen a la mente de inmediato son los árboles cuádruples y otros árboles de partición del espacio, donde la división del espacio usando solo dos nodos por nivel haría que la lógica sea innecesariamente compleja; y Árboles B utilizados en muchas bases de datos, donde el factor limitante no es cuántas comparaciones se realizan en cada nivel, sino cuántos nodos se pueden cargar desde el disco duro a la vez)

BlueRaja - Danny Pflughoeft
fuente
3
> Treap: estructura de datos aleatorios utilizada en redes inalámbricas y asignación de memoria. ¿Cómo se usan exactamente en la asignación de memoria y las redes inalámbricas?
frp
1
Hay muchas estructuras de datos y algoritmos útiles que hacen uso de la palabra "binario", y el "árbol de búsqueda binario" es de hecho uno de ellos, pero esa no es la pregunta que se hizo. ¿De qué sirve un viejo y simple "árbol binario"? No uno ordenado, ni equilibrado, ni completo. ¿Solo un viejo árbol al azar?
Michael Erickson
44
@MichaelErickson ¿Leíste la respuesta? Porque esa es exactamente la pregunta que respondí.
BlueRaja - Danny Pflughoeft
1
Creo que los Hash Trees se llaman comúnmente Merkle Trees, al menos dentro de las comunidades de bitcoin y ethereum, IPFS, etc.
Duke
1
Lástima que esta respuesta contenga tantos errores. Los árboles n-ary en hardware moderno son casi siempre preferibles a los árboles binarios. Las aplicaciones nombradas en su mayoría no usan árboles binarios.
Stephan Eggermont
290

Cuando la mayoría de las personas hablan de árboles binarios, la mayoría de las veces piensan en árboles de búsqueda binarios , así que lo cubriré primero.

Un árbol de búsqueda binario no equilibrado es realmente útil para poco más que educar a los estudiantes sobre las estructuras de datos. Esto se debe a que, a menos que los datos lleguen en un orden relativamente aleatorio, el árbol puede degenerar fácilmente en su peor forma, que es una lista vinculada, ya que los árboles binarios simples no están equilibrados.

Un buen ejemplo: una vez tuve que arreglar algún software que cargaba sus datos en un árbol binario para su manipulación y búsqueda. Escribió los datos en forma ordenada:

Alice
Bob
Chloe
David
Edwina
Frank

para que, al volver a leerlo, terminara con el siguiente árbol:

  Alice
 /     \
=       Bob
       /   \
      =     Chloe
           /     \
          =       David
                 /     \
                =       Edwina
                       /      \
                      =        Frank
                              /     \
                             =       =

cual es la forma degenerada Si buscas a Frank en ese árbol, tendrás que buscar los seis nodos antes de encontrarlo.

Los árboles binarios se vuelven realmente útiles para buscar cuando los equilibras. Esto implica rotar subárboles a través de su nodo raíz para que la diferencia de altura entre dos subárboles sea menor o igual que 1. Agregar esos nombres arriba de uno a la vez en un árbol equilibrado le daría la siguiente secuencia:

1.   Alice
    /     \
   =       =

 

2.   Alice
    /     \
   =       Bob
          /   \
         =     =

 

3.        Bob
        _/   \_
   Alice       Chloe
  /     \     /     \
 =       =   =       =

 

4.        Bob
        _/   \_
   Alice       Chloe
  /     \     /     \
 =       =   =       David
                    /     \
                   =       =

 

5.           Bob
        ____/   \____
   Alice             David
  /     \           /     \
 =       =     Chloe       Edwina
              /     \     /      \
             =       =   =        =

 

6.              Chloe
            ___/     \___
         Bob             Edwina
        /   \           /      \
   Alice     =      David        Frank
  /     \          /     \      /     \
 =       =        =       =    =       =

En realidad, puede ver subárboles enteros girando hacia la izquierda (en los pasos 3 y 6) a medida que se agregan las entradas y esto le da un árbol binario equilibrado en el que la búsqueda del peor de los casos es en O(log N)lugar de la O(Nque da la forma degenerada. En ningún momento el NULL más alto ( =) difiere del más bajo en más de un nivel. Y, en el árbol final anterior, se puede encontrar Frank con sólo mirar tres nodos ( Chloe, Edwinay, por último, Frank).

Por supuesto, pueden volverse aún más útiles cuando los haces árboles multidireccionales equilibrados en lugar de árboles binarios. Eso significa que cada nodo contiene más de un elemento (técnicamente, contienen N elementos y N + 1 punteros, un árbol binario es un caso especial de un árbol multidireccional de 1 vía con 1 elemento y 2 punteros).

Con un árbol de tres vías, terminas con:

  Alice Bob Chloe
 /     |   |     \
=      =   =      David Edwina Frank
                 /     |      |     \
                =      =      =      =

Esto normalmente se usa para mantener las claves de un índice de elementos. He escrito un software de base de datos optimizado para el hardware en el que un nodo es exactamente del tamaño de un bloque de disco (por ejemplo, 512 bytes) y coloca todas las claves que puede en un solo nodo. Los punteros en este caso eran en realidad números de registro en un archivo de acceso directo de registro de longitud fija separado del archivo de índice (por lo que se Xpodía encontrar el número de registro simplemente buscando X * record_length).

Por ejemplo, si los punteros son 4 bytes y el tamaño de la clave es 10, el número de claves en un nodo de 512 bytes es 36. Eso es 36 claves (360 bytes) y 37 punteros (148 bytes) para un total de 508 bytes con 4 bytes desperdiciados por nodo.

El uso de claves de múltiples vías introduce la complejidad de una búsqueda de dos fases (búsqueda de múltiples vías para encontrar el nodo correcto combinado con una pequeña búsqueda secuencial (o binaria lineal) para encontrar la clave correcta en el nodo) pero la ventaja en haciendo menos E / S de disco más de lo que compensa esto.

No veo ninguna razón para hacer esto por una estructura en memoria, sería mejor quedarse con un árbol binario equilibrado y mantener su código simple.

También tenga en cuenta que las ventajas de O(log N)over O(N)realmente no aparecen cuando sus conjuntos de datos son pequeños. Si está utilizando un árbol multidireccional para almacenar las quince personas en su libreta de direcciones, probablemente sea exagerado. Las ventajas se obtienen cuando almacena algo como cada pedido de sus cien mil clientes en los últimos diez años.

El objetivo de la notación big-O es indicar lo que sucede a medida que se Nacerca al infinito. Algunas personas pueden estar en desacuerdo, pero incluso está bien usar el método de burbuja si está seguro de que los conjuntos de datos se mantendrán por debajo de un cierto tamaño, siempre que no haya nada más disponible :-)


En cuanto a otros usos para los árboles binarios, hay muchos, como:

  • Montones binarios donde las teclas más altas están por encima o iguales a las más bajas en lugar de a la izquierda de (o debajo o igual y a la derecha);
  • Hash trees, similar a las tablas hash;
  • Árboles de sintaxis abstractos para la compilación de lenguajes informáticos;
  • Árboles Huffman para la compresión de datos;
  • Enrutamiento de árboles para el tráfico de red.

Dada la cantidad de explicación que generé para los árboles de búsqueda, soy reticente a entrar en muchos detalles sobre los demás, pero eso debería ser suficiente para investigarlos, si lo desea.

paxdiablo
fuente
28
+1 Para tal respuesta escrita; además de presentarme a árboles multidireccionales equilibrados, algo que no había visto antes.
Tony
3
No estoy de acuerdo con su afirmación de que son útiles para poco más que educar a los estudiantes. Son bastante útiles, incluso como una simple estructura de datos estáticos. Sin embargo, esta es una respuesta muy bien escrita e ilustrada, por lo que +1 para todo lo demás. :-)
Benson
1
En el hardware moderno, casi todos los árboles deben ser multidireccionales.
Stephan Eggermont
89

La organización del código Morse es un árbol binario.

árbol binario

código Morse

IliasT
fuente
44
Esta es mi respuesta favorita. Ilustra directamente la reducción en la complejidad computacional requerida para llegar a los personajes más adelante en la lista.
Bigote
77
Realmente disfruté esta respuesta!
Duncan Edwards
2
Solía ​​trabajar para una empresa que fabricaba filtros para radioaficionados, esto me lleva "de regreso" ...
JosephDoggie
62

Un árbol binario es una estructura de datos en árbol en la que cada nodo tiene como máximo dos nodos secundarios, generalmente distinguidos como "izquierda" y "derecha". Los nodos con hijos son nodos principales, y los nodos secundarios pueden contener referencias a sus padres. Fuera del árbol, a menudo hay una referencia al nodo "raíz" (el antepasado de todos los nodos), si existe. Se puede llegar a cualquier nodo en la estructura de datos comenzando en el nodo raíz y siguiendo repetidamente las referencias al hijo izquierdo o derecho. En un árbol binario, un grado de cada nodo es máximo dos.

Árbol binario

Los árboles binarios son útiles porque, como puede ver en la imagen, si desea encontrar algún nodo en el árbol, solo tiene que buscar un máximo de 6 veces. Si quisiera buscar el nodo 24, por ejemplo, comenzaría en la raíz.

  • La raíz tiene un valor de 31, que es mayor que 24, por lo que debe ir al nodo izquierdo.
  • El nodo izquierdo tiene un valor de 15, que es menor que 24, por lo que debe ir al nodo derecho.
  • El nodo derecho tiene un valor de 23, que es menor que 24, por lo que debe ir al nodo derecho.
  • El nodo derecho tiene un valor de 27, que es mayor que 24, por lo que debe ir al nodo izquierdo.
  • El nodo izquierdo tiene un valor de 25, que es mayor que 24, por lo que debe ir al nodo izquierdo.
  • El nodo tiene un valor de 24, que es la clave que estamos buscando.

Esta búsqueda se ilustra a continuación: Búsqueda de árboles

Puede ver que puede excluir la mitad de los nodos de todo el árbol en la primera pasada. y la mitad del subárbol izquierdo en el segundo. Esto hace búsquedas muy efectivas. Si esto se hiciera en 4 mil millones de elementos, solo tendría que buscar un máximo de 32 veces. Por lo tanto, cuantos más elementos contenga el árbol, más eficiente puede ser su búsqueda.

Las eliminaciones pueden volverse complejas. Si el nodo tiene 0 o 1 hijo, simplemente se trata de mover algunos punteros para excluir el que se va a eliminar. Sin embargo, no puede eliminar fácilmente un nodo con 2 hijos. Entonces tomamos un atajo. Digamos que queríamos eliminar el nodo 19.

Eliminar 1

Dado que tratar de determinar dónde mover los punteros izquierdo y derecho no es fácil, encontramos uno para sustituirlo. Vamos al subárbol izquierdo y vamos tan a la derecha como podamos. Esto nos da el siguiente valor más grande del nodo que queremos eliminar.

Eliminar 3

Ahora copiamos todo el contenido de 18, excepto los punteros izquierdo y derecho, y eliminamos el nodo 18 original.

Eliminar 4


Para crear estas imágenes, implementé un árbol AVL, un árbol de equilibrio automático, de modo que en cualquier momento, el árbol tiene como máximo un nivel de diferencia entre los nodos de la hoja (nodos sin hijos). Esto evita que el árbol se sesgue y mantiene el O(log n)tiempo máximo de búsqueda, con el costo de un poco más de tiempo requerido para las inserciones y eliminaciones.

Aquí hay una muestra que muestra cómo mi árbol AVL se ha mantenido lo más compacto y equilibrado posible.

ingrese la descripción de la imagen aquí

En una matriz ordenada, las búsquedas aún tomarían O(log(n)), al igual que un árbol, pero la inserción y eliminación aleatorias tomarían O (n) en lugar de las del árbol O(log(n)). Algunos contenedores STL usan estas características de rendimiento para su ventaja, por lo que los tiempos de inserción y extracción toman un máximo de O(log n), lo cual es muy rápido. Algunos de estos recipientes son map, multimap, set, y multiset.

El código de ejemplo para un árbol AVL se puede encontrar en http://ideone.com/MheW8

Drise
fuente
55
Solo tiene que buscar O (log n) si se trata de un árbol de búsqueda binario (que está bien equilibrado). Los árboles binarios arbitrarios no tienen restricciones de orden, y un BST aleatorio tiene complejidad de búsqueda O (log h ).
dlev
Esos no son del tipo almacenado en los contenedores estándar relevantes.
Cachorro
12

La aplicación principal es árboles de búsqueda binarios . Se trata de una estructura de datos en la que la búsqueda, inserción y eliminación son muy rápidas (sobre log(n)operaciones)

BlueRaja - Danny Pflughoeft
fuente
1
Los árboles de búsqueda binarios no son una aplicación, sino un tipo particular de árbol binario.
nbro
@nbro: Estás argumentando una semántica sin sentido, ambas son formas válidas de decir lo mismo. Tenga en cuenta que "aplicación" aquí no significa lo mismo que "aplicación informática"
BlueRaja - Danny Pflughoeft
Creo que la pregunta estaba más relacionada con aplicaciones del mundo real y no con implementaciones específicas o tipos particulares de árboles binarios. Y, por cierto, el interlocutor no pregunta qué estructuras de datos son árboles binarios particulares. No tiene sentido, OMI. Pero estoy de acuerdo que es ambiguo de todos modos. Por ejemplo, en su otra respuesta, menciona árboles de sintaxis, que es una aplicación de la estructura de datos del árbol (pero no necesariamente binaria ) en una aplicación real. Según su razonamiento, podría enumerar todos los árboles binarios que conozco, todos estaríamos contentos por la cantidad de elementos.
nbro
11

Un ejemplo interesante de un árbol binario que no se ha mencionado es el de una expresión matemática evaluada de forma recursiva. Es básicamente inútil desde un punto de vista práctico, pero es una forma interesante de pensar en tales expresiones.

Básicamente, cada nodo del árbol tiene un valor que es inherente a sí mismo o se evalúa de forma recursiva operando en los valores de sus hijos.

Por ejemplo, la expresión (1+3)*2se puede expresar como:

    *
   / \
  +   2
 / \
1   3

Para evaluar la expresión, solicitamos el valor del padre. Este nodo a su vez obtiene sus valores de sus hijos, un operador más y un nodo que simplemente contiene '2'. El operador más a su vez obtiene sus valores de los hijos con los valores '1' y '3' y los agrega, devolviendo 4 al nodo de multiplicación que devuelve 8.

Este uso de un árbol binario es similar a la notación polaca inversa en cierto sentido, en el sentido de que el orden en que se realizan las operaciones es idéntico. También una cosa a tener en cuenta es que no necesariamente tiene que ser un árbol binario, es solo que los operadores más utilizados son binarios. En su nivel más básico, el árbol binario aquí es, de hecho, un lenguaje de programación puramente funcional muy simple.

Despistado
fuente
9

No creo que haya ningún uso para los árboles binarios "puros". (excepto para fines educativos) Árboles binarios equilibrados, como árboles Rojo-Negros o árboles AVL son mucho más útiles, ya que garantizan operaciones O (log). Los árboles binarios normales pueden terminar siendo una lista (o casi una lista) y no son realmente útiles en aplicaciones que utilizan muchos datos.

Los árboles equilibrados se usan a menudo para implementar mapas o conjuntos. También se pueden usar para ordenar en O (nlogn), incluso aunque existan mejores formas de hacerlo.

También para buscar / insertar / eliminar se pueden usar tablas Hash , que generalmente tienen un mejor rendimiento que los árboles de búsqueda binarios (balanceados o no).

Una aplicación en la que los árboles de búsqueda binarios (equilibrados) serían útiles sería si se necesitara buscar / insertar / eliminar y ordenar. La ordenación podría estar en su lugar (casi, ignorando el espacio de pila necesario para la recursión), dado un árbol equilibrado de compilación listo. Todavía sería O (nlogn) pero con un factor constante más pequeño y no se necesita espacio adicional (excepto para la nueva matriz, suponiendo que los datos deben colocarse en una matriz). Las tablas de hash, por otro lado, no se pueden ordenar (al menos no directamente).

Quizás también son útiles en algunos algoritmos sofisticados para hacer algo, pero no me viene a la mente nada. Si encuentro más, editaré mi publicación.

Otros árboles como los árboles fe B + son ampliamente utilizados en bases de datos

Jorge
fuente
9

Una de las aplicaciones más comunes es almacenar eficientemente los datos en forma ordenada para acceder y buscar elementos almacenados rápidamente. Por ejemplo, std::mapo std::seten la biblioteca estándar de C ++.

El árbol binario como estructura de datos es útil para diversas implementaciones de analizadores de expresiones y solucionadores de expresiones.

También se puede usar para resolver algunos de los problemas de la base de datos, por ejemplo, la indexación.

En general, el árbol binario es un concepto general de una estructura de datos basada en un árbol particular y se pueden construir varios tipos específicos de árboles binarios con diferentes propiedades.

mloskot
fuente
7

En C ++ STL, y muchas otras bibliotecas estándar en otros lenguajes, como Java y C #. Los árboles de búsqueda binarios se utilizan para implementar conjuntos y mapas.

Yin Zhu
fuente
2
en realidad, los conjuntos / mapas de C ++ se basan más comúnmente en árboles rojo-negros, que es un árbol de búsqueda binario con un par de restricciones más.
Idan K
6

Una de las aplicaciones más importantes de los árboles binarios son los árboles de búsqueda binarios balanceados como:

Este tipo de árboles tiene la propiedad de que la diferencia en las alturas del subárbol izquierdo y el subárbol derecho se mantiene pequeña haciendo operaciones como rotaciones cada vez que se inserta o elimina un nodo.

Debido a esto, la altura total del árbol permanece del orden de log n y las operaciones como la búsqueda, inserción y eliminación de los nodos se realizan en tiempo O (log n). El STL de C ++ también implementa estos árboles en forma de conjuntos y mapas.

rohit
fuente
5

Se pueden usar como una forma rápida de ordenar datos. Inserte datos en un árbol de búsqueda binario en O (log (n)). Luego atraviesa el árbol para ordenarlos.

Aaron
fuente
2

la sintaxis de sus programas, o de hecho muchas otras cosas, como los lenguajes naturales, se pueden analizar utilizando el árbol binario (aunque no necesariamente).

Cualquier maíz
fuente
2

Implementaciones de java.util.Set

romano
fuente
2

En el hardware moderno, un árbol binario casi siempre es subóptimo debido al mal comportamiento de la memoria caché y el espacio. Esto también se aplica a las variantes (semi) equilibradas. Si los encuentra, es donde el rendimiento no cuenta (o está dominado por la función de comparación), o es más probable por razones históricas o de ignorancia.

Stephan Eggermont
fuente
2
¿Subóptimo comparado con qué?
Árboles multidireccionales. La búsqueda lineal a través de todos los datos que obtiene de un acceso a la memoria es mucho más rápido que hacer un nuevo acceso a la memoria principal
Stephan Eggermont
Quiero creerte, pero no hay nada en tu respuesta que respalde tus afirmaciones. Fuentes, gran notación, o algo así. Por favor elabora.
PhilT hace
@PhilT en.wikipedia.org/wiki/CPU_cache
Stephan Eggermont
0

Un compilador que usa un árbol binario para una representación de un AST, puede usar algoritmos conocidos para analizar el árbol como postorder, inorder. El programador no necesita crear su propio algoritmo. Debido a que un árbol binario para un archivo fuente es más alto que el árbol n-ario, su construcción lleva más tiempo. Tome esta producción: selstmnt: = "if" "(" expr ")" stmnt "ELSE" stmnt En un árbol binario tendrá 3 niveles de nodos, pero el árbol n-ary tendrá 1 nivel (de chids)

Es por eso que los sistemas operativos basados ​​en Unix son lentos.

evenhorizon
fuente