¿Existe una estructura de datos para la manipulación rápida de listas y consultas de pedidos?

9

Tenemos un conjunto, , de listas de elementos del conjunto . Cada elemento de aparece en una única lista en . Estoy buscando una estructura de datos que pueda realizar las siguientes actualizaciones:N = { 1 , 2 , 3 , . . . , n } N LLN={1,2,3,...,n}NL

  1. concat(x,y) : concatena la lista que contiene al final de la lista que contienexyx

  2. split(x) : divide la lista que contiene directamente después dexxx

También debe realizar las siguientes consultas:

  1. follows(x,y) : devuelve si e están en la misma lista e viene después de (pero no es necesariamente adyacente a )x y y x xtruexyyxx

  2. first(x) : devuelve el primer elemento de la lista que contienex

  3. next(x) : devuelve el siguiente elemento después de en la lista que contienexxx

Ya se me ocurrió una estructura de datos que realiza estas actualizaciones en y consultas en tiempo . Estoy interesado principalmente en si ya existe una estructura de datos que pueda hacer esto (¿ojalá más rápido?).O ( lO(lg2(n))O(lg(n))

Motivación: los bosques dirigidos enraizados pueden representarse con dos de estos conjuntos de listas y permiten un cálculo rápido de la accesibilidad en dichos bosques. Quiero ver para qué más se pueden usar y si todo esto ya se sabe.

bbejot
fuente

Respuestas:

11

Mantenga sus enteros en listas de omisión. Las listas de omisión normales se ordenan por clave, pero las usaremos como una representación de secuencias. Además, mantenga una matriz de punteros de tamaño . Cada elemento de la matriz debe apuntar a un nodo en una lista de omisión. Creo que esto es compatible a en y todas las demás operaciones en .n e x t O ( 1 ) O ( lg n )nnextO(1)O(lgn)

Específicamente:

  • s p l i t O ( lg n ) O ( lg n )concat o dos listas de omisión lleva tiempo y, por lo tanto, invalida a lo sumo los punteros .splitO(lgn)O(lgn)
  • O ( 1 )next solo sigue el puntero hacia adelante en el nivel de la hoja, tomando tiempo .O(1)
  • O ( lg n )first toma tiempo: siga los punteros hasta que se atasque, luego siga el puntero izquierdo. Cuando no puede seguir más punteros izquierdos, está en el puntero principal de su lista de omisión. Siga los punteros hacia abajo hasta la hoja, luego uno hacia adelante. Este es el primer elemento en la lista.O(lgn)
  • follows es algo más complicado. Proceda como en para , pero registre una lista de los valores donde se atasca (es decir, donde ya no puede seguir los punteros). Llamaremos a esta lista que grabe un "rastro". Haga lo mismo para , pero siga los punteros a la derecha cuando se atasque, no a la izquierda. Si precede a , sus trazas se intersectarán. Las trazas son de tamaño . Si cada elemento en la traza se anota con el nivel atascado, podemos verificar una intersección en el tiempo .firstyxxyO(lgn)O(lgn)

next es el peor de los casos , todos los demás son con alta probabilidad . Se pueden hacer el peor de los casos mediante el uso de listas de salto deterministas.O(1)O(lgn)

Creo que se puede hacer mediante el uso de árboles vinculados a nivel de hoja (2,5) y traspasar las espinas. Para el truco de arranque, vea " Representaciones puramente funcionales de listas ordenadas ordenables " por Kaplan y Tarjan.concatO(lglgn)

jbapple
fuente
frio. Estaba pensando en las listas de omisión, pero no podía ver cómo seguir sin los valores clave asociados.
Sasho Nikolov
Esto es genial; Veo cómo hacer que todas las actualizaciones sean deterministas , lo cual es bueno. Tendré que seguir leyendo para entender el O (lg lg (n)). Gracias por la publicación @jbapple. O(lg(n))
bbejot
1

El problema ancestral menos común se puede usar para resolver el problema de accesibilidad en árboles dinámicos enraizados, por lo que imagino que también le interesará lo siguiente: Algoritmos óptimos para encontrar antepasados ​​comunes más cercanos en árboles dinámicos , por Alstrup y Thorup. Este documento proporciona un límite de tiempo de para enlaces y consultas nca en una máquina de puntero. n mO(n+mloglogn)nm

Shaun Harker
fuente
Gracias por la referencia. El problema ancestral común más cercano ciertamente resuelve la accesibilidad en los árboles. El documento al que se vinculó describe un árbol incremental con todas las operaciones en tiempo . Me pregunto si también se puede mejorar para trabajar con árboles totalmente dinámicos. O(lglg(n))
bbejot