Heim > Artikel > Web-Frontend > Detaillierte Erläuterung des Javascript-Trie-Präfixbaumcodes
Dieser Artikel stellt hauptsächlich Beispiele für JavaScript-Trie-Wortsuchbäume vor. Er hat einen gewissen Referenzwert und kann jedem helfen.
Einführung
Der Trie-Baum (aus dem Wort „Retrieval“), auch Präfixwort, Wortsuchbaum, Wörterbuchbaum genannt, ist eine Baumstruktur, eine haha-Variante des griechischen Baums, einer Struktur aus mehreren Bäumen, die zum schnellen Auffinden verwendet wird.
Seine Vorteile sind: Minimierung unnötiger Zeichenfolgenvergleiche und eine höhere Abfrageeffizienz als bei Hash-Tabellen.
Die Kernidee von Trie ist der Austausch von Raum gegen Zeit. Verwenden Sie das gemeinsame Präfix von Zeichenfolgen, um den Zeitaufwand für Abfragen zu reduzieren und die Effizienz zu verbessern.
Der Trie-Baum hat auch seine Mängel. Unter der Annahme, dass wir nur Buchstaben und Zahlen verarbeiten, hat jeder Knoten mindestens 52+10 untergeordnete Knoten. Um Speicherplatz zu sparen, können wir verknüpfte Listen oder Arrays verwenden. In JS verwenden wir Arrays direkt, da JS-Arrays dynamisch sind und über eine integrierte Optimierung verfügen.
Grundlegende Eigenschaften
Der Wurzelknoten enthält keine Zeichen und jeder untergeordnete Knoten außer dem Wurzelknoten enthält ein Zeichen
Vom Wurzelknoten zu einem bestimmten Knoten. Die auf dem Pfad übergebenen Zeichen sind verbunden, was die Zeichenfolge ist, die dem Knoten entspricht
Alle Unterknoten jedes Knotens enthalten unterschiedliche Zeichen
Programmimplementierung
// by 司徒正美 class Trie { constructor() { this.root = new TrieNode(); } isValid(str) { return /^[a-z1-9]+$/i.test(str); } insert(word) { // addWord if (this.isValid(word)) { var cur = this.root; for (var i = 0; i < word.length; i++) { var c = word.charCodeAt(i); c -= 48; //减少”0“的charCode var node = cur.son[c]; if (node == null) { var node = (cur.son[c] = new TrieNode()); node.value = word.charAt(i); node.numPass = 1; //有N个字符串经过它 } else { node.numPass++; } cur = node; } cur.isEnd = true; //樯记有字符串到此节点已经结束 cur.numEnd++; //这个字符串重复次数 return true; } else { return false; } } remove(word){ if (this.isValid(word)) { var cur = this.root; var array = [], n = word.length for (var i = 0; i < n; i++) { var c = word.charCodeAt(i); c = this.getIndex(c) var node = cur.son[c]; if(node){ array.push(node) cur = node }else{ return false } } if(array.length === n){ array.forEach(function(){ el.numPass-- }) cur.numEnd -- if( cur.numEnd == 0){ cur.isEnd = false } } }else{ return false } } preTraversal(cb){//先序遍历 function preTraversalImpl(root, str, cb){ cb(root, str); for(let i = 0,n = root.son.length; i < n; i ++){ let node = root.son[i]; if(node){ preTraversalImpl(node, str + node.value, cb); } } } preTraversalImpl(this.root, "", cb); } // 在字典树中查找是否存在某字符串为前缀开头的字符串(包括前缀字符串本身) isContainPrefix(word) { if (this.isValid(word)) { var cur = this.root; for (var i = 0; i < word.length; i++) { var c = word.charCodeAt(i); c -= 48; //减少”0“的charCode if (cur.son[c]) { cur = cur.son[c]; } else { return false; } } return true; } else { return false; } } isContainWord(str) { // 在字典树中查找是否存在某字符串(不为前缀) if (this.isValid(word)) { var cur = this.root; for (var i = 0; i < word.length; i++) { var c = word.charCodeAt(i); c -= 48; //减少”0“的charCode if (cur.son[c]) { cur = cur.son[c]; } else { return false; } } return cur.isEnd; } else { return false; } } countPrefix(word) { // 统计以指定字符串为前缀的字符串数量 if (this.isValid(word)) { var cur = this.root; for (var i = 0; i < word.length; i++) { var c = word.charCodeAt(i); c -= 48; //减少”0“的charCode if (cur.son[c]) { cur = cur.son[c]; } else { return 0; } } return cur.numPass; } else { return 0; } } countWord(word) { // 统计某字符串出现的次数方法 if (this.isValid(word)) { var cur = this.root; for (var i = 0; i < word.length; i++) { var c = word.charCodeAt(i); c -= 48; //减少”0“的charCode if (cur.son[c]) { cur = cur.son[c]; } else { return 0; } } return cur.numEnd; } else { return 0; } } } class TrieNode { constructor() { this.numPass = 0;//有多少个单词经过这节点 this.numEnd = 0; //有多少个单词就此结束 this.son = []; this.value = ""; //value为单个字符 this.isEnd = false; } }
Konzentrieren wir uns auf die Einfügemethode von TrieNode und Trie. Da der Wörterbuchbaum hauptsächlich für die Worthäufigkeitsstatistik verwendet wird, verfügt er über viele Knotenattribute, einschließlich numPass und numEnd, aber sehr wichtige Attribute.
Die Einfügemethode wird zum Einfügen schwerer Wörter verwendet. Bevor wir beginnen, müssen wir feststellen, ob das Wort zulässig ist. Sonderzeichen und Leerzeichen dürfen nicht vorkommen. Beim Einfügen werden Zeichen aufgebrochen und in jedem Knoten platziert. numPass muss jedes Mal geändert werden, wenn ein Knoten übergeben wird.
Optimierung
Jetzt gibt es in jeder unserer Methoden eine Operation von c=-48. Tatsächlich gibt es andere Zeichen zwischen Zahlen, Großbuchstaben und Kleinbuchstaben Dies führt zu unnötiger Platzverschwendung
// by 司徒正美 getIndex(c){ if(c < 58){//48-57 return c - 48 }else if(c < 91){//65-90 return c - 65 + 11 }else {//> 97 return c - 97 + 26+ 11 } }
Dann besteht die relevante Methode darin, c-= 48 in c = this.getIndex(c)
Testvar trie = new Trie(); trie.insert("I"); trie.insert("Love"); trie.insert("China"); trie.insert("China"); trie.insert("China"); trie.insert("China"); trie.insert("China"); trie.insert("xiaoliang"); trie.insert("xiaoliang"); trie.insert("man"); trie.insert("handsome"); trie.insert("love"); trie.insert("Chinaha"); trie.insert("her"); trie.insert("know"); var map = {} trie.preTraversal(function(node, str){ if(node.isEnd){ map[str] = node.numEnd } }) for(var i in map){ console.log(i+" 出现了"+ map[i]+" 次") } console.log("包含Chin(包括本身)前缀的单词及出现次数:"); //console.log("China") var map = {} trie.preTraversal(function(node, str){ if(str.indexOf("Chin") === 0 && node.isEnd){ map[str] = node.numEnd } }) for(var i in map){ console.log(i+" 出现了"+ map[i]+" 次") }Vergleich von Trie-Baum und anderen Datenstrukturen
Zweigkomprimierung: Für einen stabilen Trie-Baum werden grundsätzlich Such- und Lesevorgänge ausgeführt, und einige Zweige können komprimiert werden. Beispielsweise kann das Inn des Zweigs ganz rechts in der vorherigen Abbildung direkt in einen Knoten „inn“ komprimiert werden, ohne als regulärer Teilbaum zu existieren. Der Radix-Baum basiert auf diesem Prinzip, um das Problem zu lösen, dass der Trie-Baum zu tief ist.
Knotenzuordnungstabelle: Diese Methode wird auch verwendet, wenn die Knoten des Trie-Baums möglicherweise fast vollständig für jeden Zustand des Knotens im Trie-Baum bestimmt wurden, wenn die Gesamtzahl der Zustände viele Male wiederholt wird Durch ein Element, das als mehrdimensionales Array von Zahlen dargestellt wird (z. B. Triple Array Trie), wird der Platzaufwand für die Speicherung des Trie-Baums selbst geringer, obwohl eine zusätzliche Zuordnungstabelle eingeführt wird.
Anwendung des Präfixbaums
Der Präfixbaum ist immer noch leicht zu verstehen und seine Anwendung ist auch sehr breit.
(1) Schnelles Abrufen von Zeichenfolgen
Die Abfragezeitkomplexität des Wörterbuchbaums beträgt O(logL), wobei L die Länge der Zeichenfolge ist. Der Wirkungsgrad ist also immer noch relativ hoch. Wörterbuchbäume sind effizienter als Hashtabellen.
(2) String-Sortierung
Aus der obigen Abbildung können wir leicht erkennen, dass die Wörter sortiert sind und zuerst die alphabetische Reihenfolge durchlaufen wird. Reduzieren Sie unnötige gemeinsame Teilzeichenfolgen.
(3) Das längste gemeinsame Präfix
Das längste gemeinsame Präfix von inn und int ist in. Beim Durchlaufen des Wörterbuchbaums zum Buchstaben n ist das gemeinsame Präfix dieser Wörter in.
(4) Präfixe automatisch abgleichen und Suffixe anzeigen
Wenn wir ein Wörterbuch oder eine Suchmaschine verwenden, geben Sie appl ein, und eine Menge Dinge mit dem Präfix appl werden automatisch angezeigt. Dann kann dies über einen Wörterbuchbaum erreicht werden. Wie bereits erwähnt, müssen wir nur die verbleibenden Suffixe durchqueren und anzeigen.
Verwandte Empfehlungen:
Über uery EasyUI kombiniert mit ztrIees Hintergrund-Seitenentwicklungs-Tutorial
Über Wörterbuchbaum-Trie in PHP-Beispiel der Implementierungsdefinitionsmethode
Word PHP implementiert Trie-Baum (Wörterbuchbaum)
Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des Javascript-Trie-Präfixbaumcodes. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!