Array-ähnliche unveränderliche (persistente) Datenstrukturimplementierung mit schneller Indizierung, Anhängen, Voranstellen und Iteration

11

Ich suche nach einer dauerhaften Datenstruktur ähnlich dem Array (aber unveränderlich), die schnelle Indizierungs-, Anhänge-, Voranstellungs- und Iterationsoperationen (gute Lokalität) ermöglicht.

Clojure bietet dauerhaften Vektor, ist jedoch nur zum schnellen Anhängen geeignet. Scalas Vektor hat effektiv ein zeitlich konstantes Anhängen und Voranstellen, aber ich kann nicht verstehen, wie es implementiert ist, da es auf derselben Datenstruktur (Bitmap-Vektor-Trie) wie der Clojure-Vektor und, wie ich verstehe, auf Bit-Mapping-Vektor-Trie basiert kann ohne schnelle Tricks nicht schnell voranstellen.

Ich bin nicht an einer gebrauchsfertigen Implementierung interessiert, sondern an einer Beschreibung, wie eine solche Datenstruktur selbst implementiert werden kann.

Tvaroh
quelle

Antworten:

13

Der offensichtliche Kandidat ist ein beständiger ausgeglichener Binärbaum. Alle von Ihnen aufgelisteten Vorgänge können mithilfe von Pfadkopien in oder O ( lg n ) -Zeit ausgeführt werden . Weitere Informationen zum Erreichen dieser Laufzeit finden Sie in Chris Okasakis Buch, auf das unten verwiesen wird, oder in meiner Antwort hier .Ö(1)Ö(lgn)

Natürlich könnte als Variante jedes Blatt eines solchen Baumes selbst ein unveränderliches Array enthalten (eine Folge aufeinanderfolgender Werte). Dies macht das Aktualisieren eines Werts weniger effizient, kann jedoch für Ihre Situation gut funktionieren, wenn Sie niemals beabsichtigen, einen vorhandenen Wert zu ändern, sondern nur anhängen und voranstellen. Auf diese Weise wird Ihr Vektor als eine Folge unveränderlicher Sequenzen dargestellt, dargestellt als ausgeglichener Binärbaum mit unveränderlichen Arrays in den Blättern. Dies ermöglicht eine schnelle Indizierung (logarithmisch in der Anzahl der Blätter), ein schnelles Anhängen und Voranstellen sowie eine schnelle Iteration. Die asymptotische Komplexität im schlimmsten Fall ist nicht besser, aber die Leistung in der Praxis könnte erheblich besser sein.

Die Standardreferenz ist Chris Okasakis 1998 erschienenes Buch "Rein funktionale Datenstrukturen".
Siehe auch

DW
quelle
Vielen Dank. Es sieht so aus, als wären RRB-Bäume ein guter Kandidat und sie haben bereits eine (nicht vollständige) Clojure-Implementierung.
Tvaroh
Ich denke, Okasaki sagt uns, wie wir diese Laufzeiten unter Unveränderlichkeit und Ausdauer erreichen können.
Raphael
1
@ Raphael, yup. Ich habe Referenzen hinzugefügt, um zu erklären, wie Sie die Laufzeit erreichen (am Anfang meiner Antwort).
DW
4

Ich habe eine Implementierung einer solchen Datenstruktur in meinem Artikel über den inkrementellen Abgleich regulärer Ausdrücke beschrieben - siehe http://jkff.info/articles/ire/#ropes-strings-with-fast-concatenation und den Text unter und über diesem Abschnitt .

Es ist eine Vielzahl von Bäumen mit konstanter Höhe (wie B-Bäume oder 2-3 Bäume). Grundsätzlich handelt es sich um einen (2,3) -Baum, dessen Blätter (N, 2N-1) -Arrays sind, um einen Overhead pro Element zu vermeiden. (Ein (N, 2N-1) -Array ist ein Array, dessen Längen im Bereich N..2N-1 liegen.) Größeres N führt zu einem geringeren Overhead, erhöht jedoch linear die Komplexität der Aufteilung und Verkettung. Operationen wie Indizieren, Teilen und Verketten sind der Arbeitsweise in 2-3 Bäumen sehr ähnlich und verallgemeinern sich auf Blattebene auf (N, 2N-1).

jkff
quelle
Links brechen; Bitte geben Sie eine korrekte Referenz an (damit die Leute Ihr Papier ohne den Link finden können).
Raphael
Ich habe das Papier in keiner Zeitschrift veröffentlicht, nur auf meiner persönlichen Website. Sollte es aber wahrscheinlich auf Arxiv setzen, gute Idee.
JKFF
Ich habe hauptsächlich über Autor (en), Titel und Jahr nachgedacht - das macht das Googeln bei Bedarf einfacher. Es wäre sogar noch besser, es auf arXiv zu setzen!
Raphael