¿Existe una estructura de datos de 'pila de cadenas' que admita estas operaciones de cadenas?

28

Estoy buscando una estructura de datos que almacene un conjunto de cadenas sobre un conjunto de caracteres , capaz de realizar las siguientes operaciones. Denotamos como la estructura de datos que almacena el conjunto de cadenas .D ( S ) SΣD(S)S

  • Add-Prefix-Seten : dado un conjunto de cadenas (posiblemente vacías), cuyo tamaño está limitado por una constante y cuyas longitudes de cadena están delimitadas por una constante, devuelve . Tanto estas constantes delimitadores son globales: son los mismos para todas las entradas .T D ( { t s | t T , s S } ) TD(S)TD({ts | tT,sS})T
  • Get-Prefixesen : return . Tenga en cuenta que realmente no me importa qué estructura se utiliza para este conjunto, siempre que pueda enumerar su contenido en tiempo .{ a | a s S , a Σ } O ( | Σ | )D(S){a | asS,aΣ}O(|Σ|)
  • Remove-Prefixesen : devuelve .D ( { s | a s S , a Σ } )D(S)D({s | asS,aΣ})
  • Merge: dado y , devuelve .D(S)D ( S T )D(T)D(ST)

Ahora, realmente me gustaría hacer todas estas operaciones en tiempo , pero estoy bien con una estructura que hace todas estas operaciones en tiempo , donde es la longitud de la cadena más larga en el estructura. En el caso de la fusión, me gustaría un tiempo de ejecución , donde es para el primero y el para la segunda estructura.o ( n ) n o ( n 1 + n 2 ) n 1 nO(1)o(n)no(n1+n2)n1n nn2n

Un requisito adicional es que la estructura es inmutable, o al menos que las operaciones anteriores devuelven estructuras 'nuevas' de modo que los punteros a las antiguas sigan funcionando como antes.

Una nota sobre la amortización: está bien, pero hay que estar atento a la persistencia. A medida que reutilizo estructuras viejas todo el tiempo, estaré en problemas si llego al peor de los casos con un conjunto particular de operaciones en la misma estructura (ignorando las nuevas estructuras que crea).

Me gustaría usar dicha estructura en un algoritmo de análisis en el que estoy trabajando; la estructura anterior mantendría el lookahead que necesito para el algoritmo.

Ya he considerado usar un trie , pero el problema principal es que no sé cómo fusionar los intentos de manera eficiente. Si el conjunto de cadenas para Add-Prefix-Setconsta de solo cadenas de un solo carácter, entonces podría almacenar estos conjuntos en una pila, lo que le daría tiempos de ejecución para las primeras tres operaciones. Sin embargo, este enfoque tampoco funciona para la fusión.O(1)

Finalmente, tenga en cuenta que no estoy interesado en los factores: esto es constante para todo lo que me importa.|Σ|

Alex ten Brink
fuente
¿Las cadenas solo son construidas por la operación Add-Prefix-Seto comienzas con un conjunto arbitrario de cadenas?
Joe
2
Supongamos que antes de una operación de combinación, hay una cuerda de longitud tanto en S y T . ¿Cómo podría detectar si esta cadena es o no un duplicado en o ( n 1 + n 2 ) tiempo? n1=n2STo(n1+n2)
Joe
Comienzas con un conjunto con una cadena de un solo carácter, pero una cadena vacía también está bien (puedes introducirla Add-Prefix-Set)
Alex ten Brink
@ Joe: que es una buena pregunta - estoy empezando a convencerse de la operación de fusión más o menos se rompe alguna posibilidad de conseguir una estructura de este tipo ...
Alex ten Brink
Si usa su representación de "pila de conjuntos", podría fusionar dos pilas en min (n1,n2)
Joe

Respuestas:

5

Lo pensé durante bastante tiempo, pero no encontré el problema de hacer todas sus operaciones de la manera más estúpida posible en una estructura DAG tipo trie:

Agregar conjunto de prefijos

Crear un trie de cadenas de . Conecte cada nodo de hoja a la raíz del viejo trie.T

Complejidad: O(|T|)

Unir

Unir raíces de dos estructuras: hacer que todos los nodos hijos del segundo hijo raíz del primer nodo. Ahora puede tener varias aristas marcadas con el mismo carácter desde el mismo nodo.

Complejidad: O(1)

Actualización perezosa de la raíz

  1. O(|Σ|)O(1)
  2. O(1)

Obtener prefijos

Lazy actualiza la raíz. Ahora encuentre todos los elementos secundarios de la raíz e informe el conjunto de letras en los bordes que van hacia ellos.

O(|Σ|)

Eliminar-prefijos

Lazy actualiza la raíz. Une a todos los hijos de la raíz y establece el puntero raíz al resultado de esta unión. Lazy actualiza la nueva raíz.

O(|Σ|)

Persistencia

O(1)O(|Σ|)O(logN)N

maksay
fuente