En informática , el problema de mantenimiento del orden implica mantener un conjunto totalmente ordenado que admita las siguientes operaciones:
insert(X, Y)
, que inserta X inmediatamente después de Y en el orden total;order(X, Y)
, que determina si X precede a Y en el orden total; ydelete(X)
, que elimina X del conjunto.Paul Dietz introdujo por primera vez una estructura de datos para resolver este problema en 1982. [1] Esta estructura de datos admite insert(X, Y)
in (en notación Big O ) tiempo amortizado y en tiempo constante, pero no admite la eliminación. Athanasios Tsakalidis utilizó árboles BB[α] con los mismos límites de rendimiento que admiten la eliminación en y mejoraron el rendimiento de inserción y eliminación en tiempo amortizado con indirección. [2] Dietz y Daniel Sleator publicaron una mejora al tiempo constante en el peor de los casos en 1987. [3] Michael Bender, Richard Cole y Jack Zito publicaron alternativas significativamente simplificadas en 2002. [4] Bender, Fineman, Gilbert, Kopelowitz y Montes también publicaron una solución desamortizada en 2017. [5]order(X, Y)
Las estructuras de datos eficientes para el mantenimiento de pedidos tienen aplicaciones en muchas áreas, incluidas la persistencia de estructuras de datos , [6] algoritmos de gráficos [7] [8] y estructuras de datos tolerantes a fallas. [9]
Un problema relacionado con el problema de mantenimiento del orden es el problema de etiquetado de listas en el que, en lugar de la order(X,
Y)
operación, la solución debe mantener una asignación de etiquetas de un universo de números enteros a los elementos del conjunto de modo que X preceda a Y en el orden total si y solo si a X se le asigna una etiqueta menor que Y. También debe admitir una operación que devuelva la etiqueta de cualquier nodo X. Nótese que se puede implementar simplemente comparando y de modo que cualquier solución al problema de etiquetado de listas dé inmediatamente una al problema de mantenimiento del orden. De hecho, la mayoría de las soluciones al problema de mantenimiento del orden son soluciones al problema de etiquetado de listas aumentadas con un nivel de indirección de la estructura de datos para mejorar el rendimiento. Veremos un ejemplo de esto a continuación.label(X)
order(X, Y)
label(X)
label(Y)
Para un problema de etiquetado de listas en conjuntos de tamaño hasta , el costo del etiquetado de listas depende de cuán grande sea una función de . El rango de parámetros relevante para el mantenimiento del orden es para , para el cual se conoce una solución de costo amortizado, [10] y para el cual se conoce una solución amortizada en tiempo constante [11].
La indirección es una técnica utilizada en estructuras de datos en la que un problema se divide en varios niveles de una estructura de datos para mejorar la eficiencia. Normalmente, un problema de tamaño se divide en problemas de tamaño . Por ejemplo, esta técnica se utiliza en intentos y-fast . Esta estrategia también funciona para mejorar el rendimiento de inserción y eliminación de la estructura de datos descrita anteriormente con un tiempo amortizado constante. De hecho, esta estrategia funciona para cualquier solución del problema de etiquetado de listas con tiempo de inserción y eliminación amortizado.
La nueva estructura de datos se reconstruye completamente cuando se hace demasiado grande o demasiado pequeña. Sea el número de elementos del orden total cuando se reconstruyó por última vez. La estructura de datos se reconstruye siempre que se viola el invariante mediante una inserción o eliminación. Dado que la reconstrucción se puede realizar en tiempo lineal, esto no afecta el rendimiento amortizado de las inserciones y eliminaciones.
Durante la operación de reconstrucción, los elementos del orden total se dividen en sublistas contiguas, cada una de tamaño . El problema de etiquetado de listas se resuelve en el conjunto de nodos que representan cada una de las sublistas en su orden de lista original. Las etiquetas para este subproblema se toman como polinómicas, es decir , de modo que se puedan comparar en tiempo constante y actualizar en tiempo amortizado.
Para cada sublista se construye una lista doblemente enlazada de sus elementos, almacenando con cada elemento un puntero a su representante en el árbol, así como una etiqueta entera local. Las etiquetas enteras locales también se toman de un rango , de modo que se puedan comparar en tiempo constante, pero como cada problema local involucra solo elementos, el rango de etiquetas es exponencial en el número de elementos que se etiquetan. Por lo tanto, se pueden actualizar en tiempo amortizado.
Consulte el problema de etiquetado de listas para obtener detalles de ambas soluciones.
Dados los nodos de la sublista X e Y, order(X, Y)
se puede responder comprobando primero si los dos nodos están en la misma sublista. Si es así, su orden se puede determinar comparando sus etiquetas locales. De lo contrario, se comparan las etiquetas de sus representantes en el primer problema de etiquetado de listas. Estas comparaciones toman un tiempo constante.
Dado un nuevo nodo de sublista para X y un puntero al nodo de sublista Y, insert(X, Y)
inserta X inmediatamente después de Y en la sublista de Y, si hay espacio para X en la lista, es decir, si la longitud de la lista no es mayor que después de la inserción. Su etiqueta local la proporciona el algoritmo de etiquetado de listas locales para etiquetas exponenciales. Este caso requiere tiempo amortizado.
Si la lista local se desborda, se divide de manera uniforme en dos listas de tamaño , y a los elementos de cada lista se les asignan nuevas etiquetas de sus rangos (independientes). Esto crea una nueva sublista, que se inserta en la lista de sublistas, y al nuevo nodo de la sublista se le asigna una etiqueta en la lista de sublistas mediante el algoritmo de etiquetado de listas. Finalmente, se inserta X en la lista correspondiente.
Esta secuencia de operaciones lleva tiempo, pero se han producido inserciones desde que se creó la lista o se dividió por última vez. Por lo tanto, el tiempo amortizado por inserción es .
Dado un nodo de sublista X que se va a eliminar, delete(X)
simplemente elimina X de su sublista en tiempo constante. Si esto deja la sublista vacía, entonces necesitamos eliminar el representante de la lista de sublistas. Dado que al menos
se eliminaron elementos de la sublista desde que se creó por primera vez, podemos permitirnos dedicar el tiempo; el costo amortizado de una eliminación es .