Gibt es eine 'String Stack'-Datenstruktur, die diese String-Operationen unterstützt?

28

Ich suche nach einer Datenstruktur , dass speichert einen Satz von Saiten über einen Zeichensatz , können die folgenden Operationen durchführen. Wir bezeichnen D ( S ) als die Datenstruktur, die den Satz von Zeichenketten S speichert .ΣD(S)S

  • Add-Prefix-Seton : Bei gegebener Menge T von (möglicherweise leeren) Zeichenfolgen, deren Größe durch eine Konstante und deren Zeichenfolgenlänge durch eine Konstante begrenzt ist, wird D zurückgegeben ( { t s | t T , s S } ) . Diese beiden Begrenzungskonstanten sind global: Sie sind für alle Eingänge T gleich .D(S)TD({ts | tT,sS})T
  • Get-Prefixeszu : return { a | ein s S , a & Sgr; } . Beachten Sie, dass es mir nichts ausmacht, welche Struktur für diese Menge verwendet wird, solange ich den Inhalt in O ( | Σ | ) aufzählen kann .D(S){a | asS,aΣ}O(|Σ|)
  • Remove-Prefixesauf : return D ( { s | a s S , a & Sgr; } ) .D(S)D({s | asS,aΣ})
  • Merge: Da und D ( T ) , return D ( S T ) .D(S)D(T)D(ST)

Nun, ich würde wirklich gerne alle diese Operationen in Zeit ausführen , aber ich bin mit einer Struktur einverstanden, die alle diese Operationen in O ( n ) Zeit ausführt , wobei n die Länge der längsten Zeichenfolge in der Zeichenfolge ist Struktur. Im Falle der Zusammenführung, würde Ich mag eine O ( n 1 + n 2 ) Laufzeit, wobei n 1 ist , n für die erste und n 2 der n für die zweite Struktur.O(1)o(n)no(n1+n2)n1nn2n

Eine zusätzliche Anforderung ist, dass die Struktur unveränderlich ist oder dass die obigen Operationen 'neue' Strukturen zurückgeben, so dass Zeiger auf die alten weiterhin wie zuvor funktionieren.

Ein Hinweis zur Amortisation: Das ist in Ordnung, aber Sie müssen auf Ausdauer achten. Da ich alte Strukturen immer wieder verwende, habe ich Probleme, wenn ich einen Worst-Case-Fall mit bestimmten Operationen auf derselben Struktur erleide (ignoriere also die neu erstellten Strukturen).

Ich möchte eine solche Struktur in einem Parsing-Algorithmus verwenden, an dem ich arbeite. Die obige Struktur würde den Lookahead enthalten, den ich für den Algorithmus benötige.

Ich habe bereits überlegt, einen Trie zu verwenden , aber das Hauptproblem ist, dass ich nicht weiß, wie ich Versuche effizient zusammenführen kann. Wenn der Satz von Zeichenfolgen für Add-Prefix-Setnur aus Zeichenfolgen mit einem Zeichen besteht, können Sie diese Sätze in einem Stapel speichern, wodurch Sie -Laufzeiten für die ersten drei Vorgänge erhalten. Dieser Ansatz funktioniert jedoch auch nicht für das Zusammenführen.O(1)

Schließlich ist zu beachten , dass ich nicht in Faktoren interessiert bin : das ist konstant für alles, was mich interessiert.|Σ|

Alex ten Brink
quelle
Werden Zeichenfolgen nur durch die Operation erstellt, Add-Prefix-Setoder beginnen Sie mit einem beliebigen Satz von Zeichenfolgen?
Joe
2
n1=n2STo(n1+n2)
Sie beginnen mit einem Satz mit einer einzelnen Zeichenfolge, aber eine leere Zeichenfolge ist auch in Ordnung (Sie können es einfach Add-Prefix-Setin)
Alex ten Brink
@ Joe: das ist eine gute Frage - ich fange an, überzeugt zu werden, dass die Zusammenführungsoperation so ziemlich jede Chance auf eine solche Struktur sprengt ...
Alex ten Brink
(n1,n2)

Antworten:

5

Ich habe lange nachgedacht, aber nicht das Problem gefunden, alle Operationen in einer trie-artigen DAG-Struktur so dumm wie möglich durchzuführen:

Add-Prefix-Set

T

O(|T|)

Verschmelzen

Vereinigen Sie Wurzeln zweier Strukturen: Machen Sie alle Kindknoten der zweiten Wurzel zum Kindknoten des ersten Knotens. Möglicherweise sind jetzt mehrere Kanten mit demselben Zeichen markiert, die vom selben Knoten ausgehen.

O(1)

Lazy Update der Wurzel

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

Get-Präfixe

Faul aktualisieren Sie die Wurzel. Finden Sie nun alle Kinder der Wurzel und melden Sie Buchstaben an den Kanten, die zu ihnen führen.

O(|Σ|)

Präfixe entfernen

Faul aktualisieren Sie die Wurzel. Vereinige alle Kinder der Wurzel und setze den Wurzelzeiger auf das Ergebnis dieser Vereinigung. Faul aktualisieren Sie die neue Wurzel.

O(|Σ|)

Beharrlichkeit

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

maksay
quelle