¿Por qué es std :: mapa implementa como un árbol rojo-negro?

votos
130

¿Por qué es std :: mapa implementa como un árbol rojo-negro ?

Hay varias equilibradas árboles binarios de búsqueda (BSTS) por ahí. ¿Cuáles eran compromisos de diseño en la elección de un árbol rojo-negro?

Publicado el 13/03/2011 a las 09:33
fuente por usuario
En otros idiomas...                            


6 respuestas

votos
86

Es probable que los dos algoritmos más comunes de árboles de equilibrado auto son árboles rojo-Negro y árboles AVL . Para equilibrar el árbol después de una inserción / actualización de ambos algoritmos utilizan la noción de rotaciones donde los nodos del árbol se giran para realizar el re-equilibrio.

Mientras que en los dos algoritmos del inserto operaciones de borrado / O (log n), en el caso de Rojo-Negro de rotación del árbol de reequilibrio es un (1) O la operación mientras que con AVL este es un O (log n) la operación, por lo que la árbol rojo-Negro más eficiente en este aspecto de la etapa de reequilibrio y una de las posibles razones por las que es más comúnmente utilizado.

árboles rojo-negro se utilizan en la mayoría de las bibliotecas de recogida, incluyendo las ofertas de Java y Microsoft .NET Framework.

Respondida el 13/03/2011 a las 09:47
fuente por usuario

votos
2

Es sólo la elección de su aplicación - que podrían ser implementadas como cualquier árbol de equilibrado. Las distintas opciones son comparables con pequeñas diferencias. Por tanto, cualquier es tan bueno como cualquier otro.

Respondida el 13/03/2011 a las 09:48
fuente por usuario

votos
22

árboles AVL tener una altura máxima de 1.44logn, mientras que los árboles RB tienen un máximo de 2logn. Inserción de un elemento en un AVL puede implicar un reequilibrio en un momento en el árbol. El reequilibrio termina la inserción. Después de la inserción de una nueva hoja, la actualización de los ancestros de que la hoja tiene que ser hecho hasta la raíz, o hasta un punto donde los dos subárboles son de igual profundidad. La probabilidad de tener que actualizar k nodos es 1/3 ^ k. Rebalancing es O (1). Extracción de un elemento puede implicar más de un reequilibrio (hasta la mitad de la profundidad del árbol).

RB-árboles son árboles B de orden 4 representados como árboles binarios de búsqueda. A 4-nodo en los resultados de B-árbol en dos niveles en el BST equivalente. En el peor de los casos, todos los nodos del árbol son 2-nodos, con sólo una cadena de 3-nodos abajo a una hoja. Esa hoja estará a una distancia de 2logn de la raíz.

Bajando desde la raíz hasta el punto de inserción, uno tiene que cambiar 4-nodos en 2-nodos, para asegurarse de que ninguna de inserción no se saturará una hoja. Al volver de la inserción, todos estos nodos tienen que ser analizadas para asegurarse de que representan correctamente 4-nodos. Esto también se puede hacer descender en el árbol. El costo global será la misma. ¡No hay almuerzo gratis! La eliminación de un elemento del árbol es del mismo orden.

Todos estos árboles requieren que los nodos llevan información sobre la altura, peso, color, etc. árbol biselado Sólo están exentos de tal información adicional. Pero la mayoría de la gente tiene miedo de árbol biselado, debido a la ramdomness de su estructura!

Por último, los árboles también pueden llevar información de peso en los nodos, lo que permite el equilibrio de peso. Varios esquemas se pueden aplicar. Uno debe reequilibrar cuando un subárbol contiene más de 3 veces el número de elementos del otro subárbol. Rebalancing se realiza de nuevo ya sea throuh una sola o doble rotación. Esto significa un peor caso de 2.4logn. Uno puede salirse con 2 veces en lugar de 3, una mejor relación, pero puede significar dejar un poco menos thant 1% de los subárboles desequilibrada aquí y allá. ¡Difícil!

¿Qué tipo de árbol es el mejor? AVL seguro. Ellos son los más sencillos de código, y tienen su peor altura cercana a log n. Para un árbol de 1000000 elementos, un AVL será como máximo de la altura 29, una RB 40, y un peso equilibrado 36 o 50 dependiendo de la relación.

Hay una gran cantidad de otras variables: la aleatoriedad, la relación de Agrega, elimina, búsquedas, etc.

Respondida el 16/07/2011 a las 02:52
fuente por usuario

votos
36

Realmente depende del uso. Árbol AVL por lo general tiene más rotaciones de reequilibrio. Así que si su aplicación no tiene demasiadas operaciones de inserción y supresión pesos, pero en gran medida de la búsqueda, a continuación, el árbol AVL, probablemente es una buena opción.

std::map utiliza árbol Red-Negro como se pone un razonable equilibrio entre la velocidad del nodo de inserción / deleción y búsqueda.

Respondida el 26/05/2012 a las 19:32
fuente por usuario

votos
2

Actualizar 14.06.2017: webbertiger editar su respuesta tras mi comentario. Debo señalar que su respuesta es ahora mucho mejor a mis ojos. Pero seguí mi respuesta al igual que información adicional ...

Debido al hecho de que creo que la primera respuesta es incorrecta (corrección: no tanto ya no) y el tercero tiene una afirmación equivocada. Yo sentía que tenía que aclarar las cosas ...

El árbol 2 más populares son AVL y Negro rojo (RB). La principal diferencia se encuentran en la utilización:

  • AVL: Mejor si la relación de consulta (leer) es más grande que la manipulación (modificación). huella de la memoria es un poco menos de RB (debido al bit requerida para colorear).
  • RB: Mejor en casos generales donde hay un equilibrio entre la consulta (leer) y la manipulación (modificación) o más sobre la modificación de consulta. Un poco más grande huella de la memoria debido al almacenamiento de bandera rojo-negro.

La principal diferencia proviene de la coloración. Usted tiene menos acción re-equilibrio en el árbol de RB AVL porque el colorante permite que se salte veces o acortar las acciones re-equilibrio que tienen un coste de alta relativa. Debido a la coloración, árbol RB también tienen un mayor nivel de nodos, ya que podría aceptar nodos rojos entre los negros (que tienen la posibilidad de ~ 2x niveles más) haciendo de búsqueda (leer) un poco menos eficiente ... sino porque se trata de una constante (2x), se quede en O (log n).

Si se tiene en cuenta el impacto en el rendimiento para una modificación de un árbol (significativo) VS el impacto en el rendimiento de la consulta de un árbol (casi insignificante), se convierte en algo natural a preferir RB sobre AVL para un caso general.

Respondida el 30/05/2017 a las 17:33
fuente por usuario

votos
5

Las respuestas anteriores sólo se refieren a las alternativas de árboles y negro rojo, probablemente, sólo queda por razones históricas.

¿Por qué no una tabla hash?

En un árbol un tipo sólo requiere ordenación parcial (<comparación) para ser utilizado como una clave en el mapa. Sin embargo, las tablas hash requerir que cada tipo de llave tiene una función hash definido. La integridad de los requisitos del tipo al mínimo es muy importante para la programación genérica.

El diseño de una buena tabla hash requiere un profundo conocimiento del contexto, lo que se va a utilizar. En caso de que utilice direccionamiento abierto, o encadenamiento unido? ¿Qué niveles de carga debe aceptar que antes de redimensionar? En caso de que utilice un hash caro que evita colisiones, o uno que es áspero y rápido?

(C ++ 11 no añadir tablas hash con unordered_map. Se puede ver en la documentación que requiere el establecimiento de políticas para configurar muchas de estas opciones.)

Desde el TEL no puede anticipar que es la mejor opción para su aplicación, por defecto tiene que ser más flexible. Árboles "sólo el trabajo" y escalar muy bien.

¿Qué pasa con otros árboles?

oferta rápida de búsqueda y rojo del árbol de Negro están autobalanceo a diferencia BSTs. Otro usuario ha señalado sus ventajas sobre el árbol AVL auto-equilibrio.

Alexander Stepanov (El creador de STL) dijo que iba a usar un árbol B * en lugar de un árbol Rojo-Negro si él escribió std::mapde nuevo. Esto se debe a que los nodos pueden almacenar un número arbitrario de elementos de forma contigua que es más amigable para los cachés de memoria modernas.

Uno de los mayores cambios desde entonces ha sido el crecimiento de las cachés. fallos de caché son muy costosos, por lo que la localidad de referencia es mucho más importante ahora. estructuras de datos basado en nodos, que tienen baja localidad de referencia, hacen mucho menos sentido. Si estuviera diseñando STL hoy en día, me gustaría tener un conjunto diferente de contenedores. Por ejemplo, un B * -tree en memoria es una opción mucho mejor que un árbol rojo-negro para la implementación de un contenedor asociativo. - Alexander Stepanov

Puede leer más aquí

Es un árbol o B negro rojo * siempre la mejor?

En otras ocasiones Alex ha declarado que std::vectores casi siempre la mejor lista de contenedores por razones similares. Rara vez tiene sentido utilizar std::listo std::dequeincluso para aquellas situaciones en las que nos enseñaron en la escuela (tales como la eliminación de un elemento de la mitad de la lista). std::vectores tan rápido que es mejor que esas estructuras para todo, pero n grande.

La aplicación de ese mismo razonamiento si tiene sólo un pequeño número de elementos (cientos?) Usando una std::vectory búsqueda lineal puede ser más eficiente que la aplicación del árbol de std::map. Dependiendo de la frecuencia de inserción, una ordenados std::vectorcombinarse con std::binary_searchpuede ser la opción más rápida.

Respondida el 21/12/2017 a las 21:46
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more