Existe uma estrutura de dados da 'pilha de strings' que suporta essas operações de strings?

28

Estou procurando uma estrutura de dados que armazene um conjunto de seqüências de caracteres sobre um conjunto de caracteres , capaz de executar as seguintes operações. Denota- D ( S ) como a estrutura de dados que armazena o conjunto de cadeias S .ΣD(S)S

  • Add-Prefix-Setem : dado um conjunto T de (possivelmente vazio) cordas, cujo tamanho é delimitada por uma constante e cuja cadeia comprimentos são delimitadas por uma constante, retorno D ( { t s | t T , s S } ) . Ambas as constantes delimitadoras são globais: eles são os mesmos para todas as entradas T .D(S)TD({ts | tT,sS})T
  • Get-Prefixesem : retornar { a | a s S , a Σ } . Note que eu realmente não me importo com a estrutura usada para esse conjunto, desde que eu possa enumerar seu conteúdo em O ( | Σ | ) .D(S){a | asS,aΣ}O(|Σ|)
  • Remove-Prefixesem : retorna D ( { s | a s S , a Σ } ) .D(S)D({s | asS,aΣ})
  • Merge: dado e D ( T ) , retorne D ( S T ) .D(S)D(T)D(ST)

Agora, eu realmente gostaria de fazer todas essas operações em , mas estou bem com uma estrutura que executa todas essas operações em o ( n ) , em que n é o comprimento da string mais longa no estrutura. No caso da fusão, que gostaria de um o ( n 1 + n 2 ) tempo de funcionamento, em que n 1 é n para o primeiro e n 2 o n para a segunda estrutura.O(1)o(n)no(n1+n2)n1nn2n

Um requisito adicional é que a estrutura seja imutável, ou pelo menos que as operações acima retornem estruturas 'novas', de modo que os ponteiros para as antigas ainda funcionem como antes.

Uma observação sobre amortização: tudo bem, mas você deve observar a persistência. Como reutilizo estruturas antigas o tempo todo, terei problemas se atingir o pior caso com um conjunto específico de operações na mesma estrutura (ignorando as novas estruturas criadas).

Eu gostaria de usar essa estrutura em um algoritmo de análise em que estou trabalhando; a estrutura acima conteria a aparência necessária para o algoritmo.

Já pensou em usar um trie , mas o principal problema é que eu não sei como mesclar tentativas de forma eficiente. Se o conjunto de cadeias de caracteres Add-Prefix-Setconsistir em apenas cadeias de caracteres únicos, você poderá armazenar esses conjuntos em uma pilha, o que forneceria tempo de execução para as três primeiras operações. No entanto, essa abordagem também não funciona para mesclagem.O(1)

Por fim, observe que não estou interessado em fatores : isso é constante para tudo que eu me importo.|Σ|

Alex ten Brink
fonte
As strings são construídas apenas pela operação Add-Prefix-Setou você começa com um conjunto arbitrário de strings?
23412 Joe
2
n1=n2STo(n1+n2)
Você começa com um conjunto com corda um single-char nele, mas uma cadeia vazia é muito bem também (você pode apenas Add-Prefix-Setlo em)
Alex ten Brink
@ Joe: que é uma boa pergunta - Eu estou começando a ficar convencido de que a operação de fusão praticamente breaks qualquer chance de obter uma tal estrutura ...
Alex ten Brink
(n1,n2)

Respostas:

5

Pensei por algum tempo, mas não encontrei o problema de fazer todas as suas operações da maneira mais estúpida possível em uma estrutura do DAG semelhante a um trie:

Add-Prefix-Set

T

O(|T|)

Mesclar

Unir raízes de duas estruturas: torne todos os nós filhos do segundo filho filhos do primeiro nó. Agora você pode ter várias arestas marcadas com o mesmo caractere indo do mesmo nó.

O(1)

Atualização lenta da raiz

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

Get-prefixos

Preguiçoso atualizar a raiz. Agora encontre todos os filhos da raiz e relate o conjunto de letras nas bordas que vão para eles.

O(|Σ|)

Remover prefixos

Preguiçoso atualizar a raiz. Una todos os filhos da raiz e defina o ponteiro da raiz para o resultado dessa união. Atualize preguiçosamente a nova raiz.

O(|Σ|)

Persistência

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

maksay
fonte