Ich habe ein bisschen über die folgenden Datenstrukturen gelesen:
- Bagwells ideale Hash-Versuche
- Larsons dynamische Hash-Tabellen
- Rot-schwarze Bäume
- Patricia Bäume
... und ich bin sicher, es gibt viele andere da draußen. Ich habe sehr wenig darüber gesehen, wofür jeder besser geeignet ist oder warum ich einen anderen vorziehen würde. Hier sind einige Fragen in diese Richtung:
- Welche funktionalen Wörterbuchdatenstrukturen sind wichtig zu wissen?
- Was sind die Vor- und Nachteile dieser Ansätze?
- Wann ist es sinnvoller, eine zwingendere Datenstruktur zu verwenden?
Die Nummern 2 und 3 sind jedoch die wichtigeren. :-)
Antworten:
Ich kann # 2 nicht wirklich beantworten, ohne mich zu verlaufen (es gibt zu viele Dimensionen, entlang derer Sie diese Strukturen vergleichen können), aber für # 3 ist die Antwort ziemlich einfach.
Verwenden Sie eine zwingende Datenstruktur, wenn: (a) absolut kein Aliasing vorliegt oder (b) Sie Aliasing wirklich für eine effiziente Übertragung verwenden müssen.
Wenn es überhaupt kein Aliasing Ihrer Datenstruktur gibt, nutzen Sie nicht die Tatsache, dass funktionale Datenstrukturen persistent sind. Es gibt also keinen Grund, für ihre Kosten zu bezahlen. Dieser Rat hat zwei Vorbehalte. Erstens mögen Sie die Einfachheit der Implementierung einer funktionalen Datenstruktur bevorzugen: Wenn Sie das Löschen für einen funktionierenden rot-schwarzen Baum implementieren, werden Sie verflucht, aber wenn Sie das Löschen in einem zwingenden rot-schwarzen Baum mit übergeordneten Zeigern implementieren, werden Sie über Selbstmord nachdenken. Zweitens kann die Zuweisung in einer gc-Sprache teurer sein als erwartet, da durch Schreibvorgänge Datenstrukturen aus der jungen Generation entfernt werden können. Wir haben wirklich keine gute Theorie zu Cache-Effekten und GC, daher haben Sie keine andere Wahl, als Benchmarking durchzuführen.
Zweitens, wenn Sie einen Broadcast-Kanal benötigen, ist eine gemeinsam genutzte Datenstruktur eine hervorragende Möglichkeit, dies zu tun. Mit einer zeitkonstanten Aktualisierung können Sie beliebig vielen anderen Personen mitteilen, dass sich ein Wert geändert hat. (Aus diesem Grund ist Union-Find eine so großartige Datenstruktur.) Bei einem rein funktionalen Setup müssen Sie entweder alle anderen Personen ändern oder ihnen abstrakte Zeiger in einen Zustand geben, den Sie manuell codieren (was eine Art stumpf ist) etwas zu tun).
Wenn Sie entweder nicht über Aliasing und Objektbesitz nachdenken möchten oder wenn Sie mehrere Versionen derselben Datenstruktur benötigen (Sie benötigen beispielsweise sowohl eine neue als auch eine alte Version), verwenden Sie einfach eine funktionale Datenstruktur.
Der Ort, an dem ich es am schwierigsten finde, diesem Rat zu folgen, sind Graph-Algorithmen. Es gibt viele wirklich elegante imperative Graph-Algorithmen, aber es ist häufig der Fall (z. B. beim Schreiben von Compilern), dass Sie auch Persistenz wünschen. Normalerweise versuchen die Leute, den Unterschied aufzuteilen und den coolen Imperativ-Algorithmus zu verwenden, aber versuchen, die Versionierung auf die Seite zu schrauben, um die Persistenz zu erhalten. Dies ist im Allgemeinen ziemlich schrecklich, voller Fehler und neigt dazu, den Leistungsvorteil des imperativen Algorithmus zu verlieren.
quelle
Höhenausgeglichene Binärbäume und deren Versuche sind ein guter Allround-Kompromiss. Ebenfalls:
Höhenausgeglichene Binärbäume und deren Versuche sind ein guter Kompromiss für Atomschlüssel. Versuche sind die gleichen für Schlüssel, die Sequenzen sind, z. B. String-Schlüssel.
Patricia-Bäume können um ein Vielfaches schneller sein, erlauben jedoch nur Ganzzahlschlüssel.
Hash-Versuche können um ein Vielfaches schneller sein als ausgeglichene Binärbäume, insbesondere wenn Hashing billiger als Vergleich ist und Polymorphismus einen Overhead hat (z. B. Zeichenfolgen in .NET) und das Schreiben von Zeigern in den Heap schnell ist (z. B. VMs wie JVM und CLR) eher für imperative Sprachen als für funktionale Sprachen optimiert). Hash-Versuche erlauben auch die interne Verwendung von Mutationen als Optimierung.
Rot-schwarze Bäume sind weniger wichtig, da sie keine signifikanten Vorteile gegenüber Bäumen mit ausgeglichener Höhe haben, aber den signifikanten Nachteil haben, dass sie keine effiziente Vereinigung, Kreuzung und Differenzierung ermöglichen.
Ebenso sind Fingerbäume in der Praxis nicht viel besser.
Wenn Ihr Wörterbuch einmal ausgefüllt und dann nur für Suchvorgänge verwendet wird, dh eingefroren.
Wenn Sie Leistung benötigen (eine anständige Hash-Tabelle wie .NET
Dictionary
ist normalerweise 10-40 × schneller als jedes generische rein funktionale Wörterbuch).Wenn Sie ein schwaches Wörterbuch benötigen, weil kein rein funktionales schwaches Wörterbuch bekannt ist.
quelle