Bauen trie schneller
Mache ich eine mobile app, die die Bedürfnisse von tausenden von schnell-string-suchen und Präfix überprüft. Um diese Fahrt, machte ich einen Trie aus meiner word-Liste, die hat ungefähr 180.000 Wörter.
Alles Super, aber das einzige problem ist, dass der Bau dieser riesigen trie (es hat etwa 400.000 Knoten) dauert etwa 10 Sekunden derzeit auf meinem Handy, das ist wirklich langsam.
Hier ist der code, baut die Marina.
public SimpleTrie makeTrie(String file) throws Exception {
String line;
SimpleTrie trie = new SimpleTrie();
BufferedReader br = new BufferedReader(new FileReader(file));
while( (line = br.readLine()) != null) {
trie.insert(line);
}
br.close();
return trie;
}
Den insert
Methode, die läuft auf O(length of key)
public void insert(String key) {
TrieNode crawler = root;
for(int level=0 ; level < key.length() ; level++) {
int index = key.charAt(level) - 'A';
if(crawler.children[index] == null) {
crawler.children[index] = getNode();
}
crawler = crawler.children[index];
}
crawler.valid = true;
}
Ich bin auf der Suche nach intuitiven Methoden zu bauen, die versuche schneller. Vielleicht Baue ich die versuche einfach mal mein laptop, und speichern Sie es irgendwie an der Festplatte, und aus einer Datei laden in das Telefon? Aber ich weiß nicht, wie diese umzusetzen ist.
Oder gibt es irgendwelche anderen Präfix-Daten-Strukturen, die in weniger Zeit zu bauen, haben aber ähnliche lookup-Zeit-Komplexität?
Anregungen werden geschätzt. Vielen Dank im Voraus.
BEARBEITEN
Jemand schlug vor, mit Hilfe der Java-Serialisierung. Ich habe es versucht, aber es war sehr langsam mit diesem code:
public void serializeTrie(SimpleTrie trie, String file) {
try {
ObjectOutput out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
out.writeObject(trie);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public SimpleTrie deserializeTrie(String file) {
try {
ObjectInput in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)));
SimpleTrie trie = (SimpleTrie)in.readObject();
in.close();
return trie;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
Kann dieser obige code schneller gemacht werden?
Meine versuche: http://pastebin.com/QkFisi09
Wort-Liste: http://www.isc.ro/lists/twl06.zip
Android-IDE zum ausführen von code: http://play.google.com/store/apps/details?id=com.jimmychen.app.sand
- Ich kann nicht installieren Sie die ide auf einem android gingerbread?
- Ich würde vorschlagen, zu Beginn von profiling. Zumindest Messung von dem Teil verbracht, für (1) beim Lesen der Datei, (2) Suche nach Ort in trie-und (3) eine neue Verknüpfung zu erstellen
- Hast du schon versucht die binary search Methode? Ich sah, wie gute Ergebnisse mit es.
- Ja habe ich versuche es, aber es schien nicht zu schnell. Ich brauche nur zwei Fragen: ob ein Präfix vorhanden ist, und ob ein Wort existiert. Ich brauche nicht alle strings, die aus einem Präfix. Btw, ich zählte die Anzahl der Präfix-Existenz sucht, war es etwa 10.000.. also die binary search Methode wurde langsamer, denn mit dem Kumpel, der ganze Algorithmus beendet in ~60 ms.
- OK, gut dass du eine Lösung gefunden. Ich fand nie ein Präfix Abfragen, die langsamer war als 1 Millisekunde und der gleichen für die Existenz einer einzigen Zeichenkette, aber vielleicht habe ich eine schnellere Telefon.
- Performance-Vergleich DAFSA Speicher verbraucht: 16020976 DAFSA (ms) : [100] 0 DAFSA (ms) : [10000] 5 DAFSA (ms) : [1000000] 28 --------------- trie Speicher verbraucht: 12946984 trie (ms) : [100] 0 trie (ms) : [10000] 6 trie (ms) : [1000000] 131 --------------- Liste belegter Speicher: 1761728 Liste (ms) : [100] 23 Liste (ms) : [10000] 696 Liste (ms) : [1000000] 71752 --------------- Set memory verbraucht: 2341616 Set (ms) : [100] 0 (ms) : [10000] 1 Satz (ms) : [1000000] 22
Du musst angemeldet sein, um einen Kommentar abzugeben.
Doppel-Array versucht sind sehr schnell zu laden/speichern, da alle Daten gespeichert in lineare arrays. Sie sind auch sehr schnell nachschlagen kann, aber die Insertionen können teuer werden. Ich Wette, es gibt eine Java-Implementierung irgendwo.
Auch, wenn die Daten statisch sind (D. H. Sie nicht, aktualisieren Sie es auf dem Telefon) zu prüfen, DAFSA für Ihre Aufgabe. Es ist eine der effizientesten Daten-Strukturen für die Speicherung der Worte (besser sein muss als "standard" versucht und radix versucht, sowohl für Größe und Geschwindigkeit, besser als prägnante versucht für Geschwindigkeit, oft besser als prägnante versucht, für die Größe). Es ist ein gutes C++ - Implementierung: dawgdic - Sie können es verwenden, um zu bauen DAFSA von der Kommandozeile aus und verwenden Sie dann eine Java-reader für die resultierende Datenstruktur (Beispiel-Implementierung ist hier).
return hasValue(index)
stattreturn true
sollte funktionieren). Habe ich noch nicht getestet/verwendet verknüpfte Java-Implementierung selbst; es kann gut funktionieren, für das die software geschrieben wurde, aber nicht als eine Allgemeine Java-Implementierung. Tut mir Leid, Ihre Zeit verschwenden. Dieses Python-Implementierung ist stark getestet und ich bin mir ziemlich sicher, dass es ordnungsgemäß funktioniert: github.com/kmike/DAWG-Python/blob/... - konsultieren, wenn im Zweifel.print dawg_python.DAWG().load('dawg.bin').prefixes(u'MAX')
return hasValue(index)
, hat nicht funktioniert. Ich überprüft mit C++ und Python-code. Können Sie bitte schauen Sie auf der Java-code einmal, wenn Sie Zeit haben? Sie sind wahrscheinlich die bekannteste person, mit der Umsetzung! Wenn dem nicht so ist, wo kann ich lernen, die internen Datei-Struktur der dawg, so dass ich Debuggen kann es mich?'HELLO\r'in dawg_python.DAWG().load('dawg.bin')
gibt True zurück. 2) das Zweite Problem ist, dass Sie nicht verwendet haben '-g' - option, so DAWG entstand ohne Anleitung und schnell Schlüssel Abschluss (D. H. finden Sie alle Schlüssel, die mit einem gegebenen Präfix) nicht funktioniert. Bitte beachten Sie, dass d....Präfixe(u'MAX') findet alle Wörter, die das sind Präfixe von u'MAX' (leer, weil der '\r' - Problem), nicht alle Wörter, beginnt mit u-'MAX'.hasValue(index)
zusammen wreaked das ganze Unheil. Ich kann nicht in Worten Ausdrücken, wie dankbar ich bin für all Eure Hilfe. Danke, dass Sie freundlich genug, um mir zu helfen, durch diese. Sie sind eine wunderbare person. Ich werde jetzt sendet einen pull-request auf, dass Java-repo, und von ganzem Herzen akzeptieren Sie diese wunderbare Antwort. Genießen Sie Ihren 5k! 🙂Könnten Sie speichern Sie Ihre versuche, wie ein array von Knoten, die mit Referenzen auf die untergeordneten Knoten ersetzt, mit array-Indizes. Ihr root-Knoten wäre das erste element. So könnte man auf einfache Weise speichern/laden Sie Ihre versuche vom einfachen Binär-oder text-format.
Bauen Sie gerade einen großen String[] und es Sortieren. Dann können Sie verwenden, binäre Suche, um die Position einer Zeichenfolge. Sie können auch eine Abfrage basierend auf Präfixen ohne viel Arbeit.
Präfix look-up-Beispiel:
Vergleichen Methode:
Findet ein vorkommen des Präfix im array und gibt es zurück Ort (MIN oder MAX sind meine nicht gefunden)
Bekommt ein String-array und Präfix, druckt vorkommen des Präfix im array
Hier von einem halbwegs kompakten format, für die Speicherung eines trie auf der Festplatte. Ich werde angeben, die ihm durch seine (Wirk -) Deserialisierung Algorithmus. Initialisieren Sie einen Stapel, dessen erste Inhalte sind die root-node der trie. Lesen Sie die Zeichen nacheinander ein und interpretiert Sie wie folgt vor. Die Bedeutung der Buchstaben " A-Z "zuweisen eines neuen Knoten, machen es zu einem Kind des aktuellen top-of-stack, und drücken Sie die neu zugewiesene Knoten auf dem stack". Der Buchstabe gibt an, welche position das Kind sich befindet. Die Bedeutung von Raum "legen Sie das gültig-flag des Knotens auf der Oberseite des Stapels auf "true". Die Bedeutung von einem backspace (\b) ist "pop stack".
Beispielsweise die Eingabe
gibt das Wort Liste
. Auf Ihrem desktop, erstellen die versuche, welche Methode und dann serialisieren, indem Sie die folgenden rekursiven Algorithmus (pseudocode).
Dies ist nicht eine Magische Kugel, aber wahrscheinlich können Sie verringern Ihre Laufzeit leicht durch tun eine große Speicherreservierung anstelle einer Reihe von kleinen.
Sah ich eine ~10% speedup im test Beispielcode (C++, Java nicht, sorry), wenn ich einen "Knoten-pool" anstatt auf einzelne Zuordnungen:
Versucht, die prealloate Raum alle möglichen Kinder (256), haben eine riesige Menge an Platz verschwendet. Machen Sie Ihren cache Weinen. Speichern Sie diese Zeiger, um die Kinder in eine veränderbare Datenstruktur.
Einigen versucht wird zu optimieren, indem er einen Knoten zum darstellen einer langen Kette, und brechen Sie diese Zeichenfolge nur, wenn nötig.
Statt einer einfachen Datei können Sie eine Datenbank wie sqlite und eine verschachtelte Gruppe oder celko Baum zum speichern des trie-und Sie können auch bauen ein schneller und kürzer (weniger Knoten) versuchten mit einem ternary search trie.
Ich weiß nicht, wie die Idee der Adressierung von Knoten, die durch den index im array, aber nur, weil es erfordert noch eine Ergänzung (index-Zeiger). Aber mit array vorbelegt Knoten Sie vielleicht etwas Zeit sparen für die Zuweisung und Initialisierung. Und Sie können auch sparen eine Menge Platz reservieren ersten 26 Indizes für Blattknoten. So werden Sie nicht brauchen, um zu reservieren und initialisieren 180000 Blatt-Knoten.
Auch mit Indizes Sie werden in der Lage sein, um Lesen Sie den vorbereiteten Knoten-array von der Festplatte im Binärformat. Dieser ist um ein Vielfaches schneller. Aber ich bin mir nicht sicher, wie dies zu tun auf Ihrer Sprache. Ist das Java?
Wenn Sie überprüft haben, dass Ihre Quelle das Vokabular ist sortiert, Sie können auch Zeit sparen, durch den Vergleich einige Präfix des aktuellen Strings mit der vorherigen. E. g. ersten 4 Zeichen. Wenn Sie gleich sind, können Sie beginnen, Ihre
Schleife von der 5-th-Ebene.
Ist es Raum ineffizient oder Zeit ineffizient? Wenn Sie Rollen eine Ebene versuchten dann Raum können Teil des Problems sein, wenn es mit einem mobil-Gerät. Überprüfen Sie heraus patricia/radix versucht, vor allem, wenn Sie es als Präfix look-up-tool.
Trie:
http://en.wikipedia.org/wiki/Trie
Patricia/Radix trie:
http://en.wikipedia.org/wiki/Radix_tree
Du nicht erwähnt, dass eine Sprache, aber hier sind zwei Implementierungen von Präfix versucht in Java.
Regelmäßigen versuche:
http://github.com/phishman3579/java-algorithms-implementation/blob/master/src/com/jwetherell/algorithms/data_structures/Trie.java
Patricia/Radix (Raum-effiziente) trie:
http://github.com/phishman3579/java-algorithms-implementation/blob/master/src/com/jwetherell/algorithms/data_structures/PatriciaTrie.java