trie oder ausgeglichene binäre Suchbaum zu speichern Wörterbuch?
Habe ich eine einfache Anforderung (vielleicht hypothetisch):
Ich soll zum speichern von Englisch-Wörterbuch (n Worte) und einem gegebenen Wort (Zeichen m), das Wörterbuch ist in der Lage zu sagen, wenn das Wort existiert im Wörterbuch oder nicht.
Was wäre eine geeignete Datenstruktur dafür?
einen ausgeglichenen binären Suchbaum? wie in C++ STL assoziative Datenstrukturen wie set,map
oder
ein trie auf den Saiten
Einige Komplexität der Analyse:
in einer ausgeglichenen bst wäre die Zeit (log n)*m (Vergleich von 2 Strings dauert O(m) Zeit, Zeichen für Zeichen)
in der Marina, wenn an jedem Knoten, konnten wir verzweigen in O(1) Zeit, finden wir mit O(m), aber die Annahme, dass an jedem Knoten können wir die Niederlassung in O(1) Zeit ist nicht gültig. an jedem Knoten, max Filialen möglich wäre 26. wenn wir wollen, O(1) auf einen Knoten, halten wir eine kurze array indexible auf Zeichen, die auf den einzelnen Knoten. Dies wird blow-up-Raum. Nach ein paar Stufen in die Marina, Verzweigungen reduzieren, so ist es besser, halten Sie eine verknüpfte Liste von nächsten Knoten aus, der Zeichen und Verweise.
was sieht eher praktische? andere trade-offs?
Dank,
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich würde sagen, verwenden Sie einen Trie, oder noch besser, verwenden seine mehr Raum effizient cousin der Directed Acyclic Word Graph (DAWG).
Er hat die gleiche runtime-Eigenschaften (einfügen, suchen, löschen) als Trie, sondern überlappt gemeinsamen Suffixe, wie auch die gemeinsamen Präfixe, die eine große Platzersparnis.
Ist dies C++, sollten Sie auch berücksichtigen
std::tr1::unordered_set
. (Falls du C++0x, können Siestd::unordered_set
.)Nur dieses verwendet eine hash-Tabelle intern, das würde ich Wetten, wird aus-üben jeden Baum-wie Struktur in der Praxis. Es ist auch trivial zu implementieren, denn Sie haben nichts zu implementieren.
Binäre Suche wird einfacher zu implementieren und es ist nur noch zu vergleichen mit einbeziehen zig Saiten am meisten. Gegeben wissen Sie die Daten up-front, können Sie bauen ein ausgeglichener binärer Baum, so dass die Leistung wird vorhersehbar und leicht zu verstehen.
In diesem Sinne, ich würde verwenden eine standard-Binär-Baum (wahrscheinlich mit
set
von C++, da ist das normalerweise implementiert, als ein Baum).Eine einfache Lösung ist die Speicherung des dict wie sortiert \n getrennte Wörter auf der Festplatte, in den Arbeitsspeicher zu laden und eine binäre Suche. Die einzige nicht-standard-Teil ist, dass Sie haben, um rückwärts zum Anfang ein Wort, wenn du tust, die binäre Suche.
Hier finden Sie den code! (Es wird davon ausgegangen globals
wordlist
Hinweis auf die geladene dict, undwordlist_end
die Punkte bis kurz nach dem Ende des geladenen dict.Ein großer Vorteil dieses Ansatzes ist, dass die dict gespeichert ist, in einer leicht lesbaren Art und Weise auf der Festplatte, und Sie brauchen keine Phantasie-code, um es zu laden (reserviert einen Speicherblock und read() in one go).
Wenn Sie möchten, verwenden Sie einen trie, könnten Sie einen gepackt und suffix-komprimierte Darstellung. Hier ist ein link zu einer von Donald Knuth ' s Schüler, Franklin Liang, der schrieb über diesen trick in seine Arbeit.
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.123.7018&rep=rep1&type=pdf
Es nutzt die Hälfte der Lagerung von der unkomplizierten textuellen dict-Vertretung gibt Ihnen die Geschwindigkeit eines trie, und Sie können (wie der textuellen dict Vertretung) speichern Sie das ganze auf der Festplatte und laden Sie es in einem gehen.
Den trick verwendet wird, ist zu packen, die trie-Knoten in einem einzigen array, interleaving, wenn möglich. Sowie ein neuer Zeiger (und ein end-of-word-marker-bit) in jeder array-Position wie in einem normalen trie speichern Sie den Brief, den dieser Knoten ist für-diese können Sie sagen, wenn der Knoten gültig ist für Ihren Staat oder, wenn es von einer überlappenden Knoten. Lesen Sie den verlinkten doc für eine vollere und deutlichere Erklärung, als auch einen Algorithmus für die Verpackung der trie in diesem array.
Ist es nicht trivial zu implementieren, das suffix-Komprimierung und gierig packing-Algorithmus beschrieben, aber es ist leicht genug.
Industrie-standard ist, speichern Sie das Wörterbuch in eine Hashtabelle und ein amortisiert O(1) lookup-Zeit. Raum ist nicht mehr kritisch in der Industrie vor allem aufgrund der Fortschritte in der Verteilungs-computing.
hashtable ist, wie google die Umsetzung seiner autocomplete-Funktion. Insbesondere haben alle das Präfix ein Wort als Schlüssel und legte das Wort, als der Wert in der Hashtabelle.
O(m)
Zeit (wom
ist die Länge des Schlüssels) wie mit einem Trie. In der Tat gibt es keine Daten-Struktur kann verletzen, minimum gebunden, da müssen Sie Lesen Sie den gesamten Schlüssel, um sicher zu wissen, welchen Wert Sie Auslesen wollen.