Mientras intentaba corregir un error en una biblioteca, busqué documentos para encontrar subranges en árboles rojos y negros sin éxito. Estoy considerando una solución con cremalleras y algo similar a la operación de adición habitual utilizada en algoritmos de eliminación para estructuras de datos inmutables, pero todavía me pregunto si hay un mejor enfoque que no pude encontrar, o incluso algún límite de complejidad mínima en tal operación?
Para ser claros, estoy hablando de un algoritmo que, dado un árbol rojo y negro y dos límites, producirá un nuevo árbol rojo y negro con todos los elementos del primer árbol que pertenecen a esos límites.
Por supuesto, un límite superior para la complejidad sería la complejidad de atravesar un árbol y construir el otro agregando elementos.
fuente
Respuestas:
Esta respuesta combina algunos de mis comentarios a la pregunta y los expande.
La operación de subrango en árboles rojo-negros se puede realizar en el peor de los casos O (log n), donde n es el número de elementos en el árbol original. Dado que el árbol resultante compartirá algunos nodos con el árbol original, este enfoque es adecuado solo si los árboles son inmutables (o los árboles son mutables, pero el árbol original ya no es necesario).
Primero observe que la operación de subrango puede implementarse mediante dos operaciones divididas. Aquí la operación de división toma un árbol rojo-negro T y una tecla x y produce dos árboles L y R de modo que L consista en todos los elementos de T menores que x y R los elementos de T mayores que x. Por lo tanto, nuestro objetivo ahora es implementar la operación de división en árboles rojo-negros en el peor de los casos O (log n).
¿Cómo realizamos la operación de división en árboles rojo-negros en tiempo O (log n)? Bueno, resultó que había un método bien conocido. (No lo sabía, pero no soy un experto en estructuras de datos). Considere la operación de unión , que toma dos árboles L y R de tal manera que cada valor en L es menor que cada valor en R y produce un árbol que consiste en todos los valores en L y R. La operación de unión se puede implementar en el peor de los casos O (| r L −r R | +1), donde r L y r Rson los rangos de L y R, respectivamente (es decir, el número de nodos negros en el camino desde la raíz hasta cada hoja). La operación de división se puede implementar utilizando la operación de unión O (log n) veces, y el tiempo total en el peor de los casos sigue siendo O (log n) considerando una suma telescópica.
Las secciones 4.1 y 4.2 de un libro [Tar83] de Tarjan describen cómo implementar las operaciones de unión y división en árboles rojo-negros en el peor de los casos O (log n). Estas implementaciones destruyen árboles originales, pero es fácil convertirlos en implementaciones funcionales inmutables copiando nodos en lugar de modificarlos.
Como nota al margen, los módulos Set y Map de Objective Caml proporcionan la operación dividida, así como otras operaciones estándar en árboles de búsqueda binarios balanceados (inmutables). Aunque no usan árboles rojo-negros (usan árboles de búsqueda binarios balanceados con la restricción de que la altura izquierda y la altura derecha difieren en un máximo de 2), mirar sus implementaciones también podría ser útil. Aquí está la implementación del módulo Set .
Referencias
[Tar83] Robert Endre Tarjan. Estructuras de datos y algoritmos de red . Volumen 44 de la serie de conferencias regionales CBMS-NSF en matemáticas aplicadas , SIAM, 1983.
fuente
La solución es no usar árboles rojo-negros. En árboles de visualización y árboles AVL, el código para dividir y unir es muy simple. Le remito a las siguientes URL con código java para los árboles de visualización y los árboles AVL que admiten esto. Vaya a la siguiente URL y consulte Set.java (árboles avl) y SplayTree.java (árboles splay).
ftp://ftp.cs.cmu.edu/usr/ftp/usr/sleator/splaying/
--- Danny Sleator
fuente
O(n)
? No he preguntado qué tipo de árboles tienen implementaciones de subrango simples porque eso no es un problema que tengo. Esta respuesta, aunque bien intencionada, está fuera de tema e inútil para el problema en cuestión.(Esto está destinado a ser un comentario, pero soy demasiado nuevo para dejar un comentario).
Simplemente quiero señalar que también puede estar interesado en la operación de "escisión", que devuelve el subrango como un nuevo árbol y el árbol de entrada sin el subrango como otro. Sin embargo, debe tener control sobre la representación subyacente del árbol, ya que el método conocido se basa en enlaces de nivel. La escisión se ejecuta en el tiempo logarítmico al tamaño del árbol más pequeño , aunque en el sentido amortizado ("amortizado" es iirc, porque ya no tengo acceso al papel) Ver:
K. Hoffman, K. Mehlhorn, P. Rosenstiehl y RE Tarjan, Clasificación de secuencias de Jordan en tiempo lineal utilizando árboles de búsqueda vinculados por nivel, Información y control, 68 (1986), 170–184
PD: La cita anterior proviene de la redacción del informe de Seidel. Treaps también apoyan la escisión.
fuente
No resolví los detalles, por lo que no estoy seguro de cómo la contabilidad adicional afecta el tiempo de ejecución.
fuente
O(logn)
, con lo que podría evitar la matriz temporal.