运行时Trie数据结构生成与存储和读取文件方法

问题描述

我正在为英语词典中的每个单词创建一个Trie结构。我想将此结构用于单词搜索和拼字游戏等游戏,但我不知道在运行时生成该结构的速度是否更快,或者是否应该设法将这种Trie结构扁平化为{ {1}}或JSON在运行时读入内存。

我对创建数据库或存储数据以供以后使用并不了解,因此任何建议都很棒-现在我正在查看XMLJackson。最终目标是将该应用程序移植到我的网站上的Java

解决方法

仅通过Java,就可以生成Trie结构并在您的网站上使用它,而无需使用JavaScriptTrieinsert这两种方法的简单search结构在JS中看起来像这样:

function Trie() {
    this.root = new TrieNode();
    this.insert = function(key) { 
        let length = key.length,next = this.root; 

        for (let level = 0; level < length; level++) { 
            let character = key.charAt(level); 
            if (next.children[character] == null) {
                next.children[character] = new TrieNode(); 
            }

            next = next.children[character]; 
        }
        next.endOfWord = true; 
    }
    this.search = function(key) { 
        let length = key.length,next = this.root; 

        for (let level = 0; level < length; level++) { 
            let character = key.charAt(level);

            if (next && next.children[character]) {
                next = next.children[character];
                continue;
            }
            return false;
        }

        return next && next.endOfWord;
    } 
}

function TrieNode() {
    this.children = {};
    this.endOfWord = false; 
}

使用上面的简单实现,您可以创建Trie实例并插入所需的所有单词:

const trie = new Trie();
trie.insert("hello");
trie.insert("hi");
trie.insert("help");
trie.insert("helpful");
... more words

例如,使用Node.js,您可以:

  • 从源文件中读取所有必需的单词。
  • 对于每个单词,请使用trie方法将其插入insert结构中。
  • 通过JSON从对象生成JSON.stringify(trie)
  • 将其保存到文件trie.js中,以后可以在您的页面上使用。

上述单词的结果js文件应类似于:

{
   "root":{
      "children":{
         "h":{
            "children":{
               "e":{
                  "children":{
                     "l":{
                        "children":{
                           "l":{
                              "children":{
                                 "o":{
                                    "children":{
                                       
                                    },"endOfWord":true
                                 }
                              },"endOfWord":false
                           },"p":{
                              "children":{
                                 "f":{
                                    "children":{
                                       "u":{
                                          "children":{
                                             "l":{
                                                "children":{
                                                   
                                                },"endOfWord":true
                                             }
                                          },"endOfWord":false
                                       }
                                    },"endOfWord":false
                                 }
                              },"endOfWord":true
                           }
                        },"endOfWord":false
                     }
                  },"endOfWord":false
               },"i":{
                  "children":{
                     
                  },"endOfWord":true
               }
            },"endOfWord":false
         }
      },"endOfWord":false
   }
}

要使用代码创建有效的JS文件,您需要在开头添加:const RAW_TRIE = 字符串,因此我们的文件如下所示:

const RAW_TRIE = {
   "root":{
      "children":{
         "h":{
          ...

您创建了一个原始Trie对象,可以通过将以下行添加到HTML或模板文件中来将该对象包含在页面中:

<script src="www.your-domain.com/path/to/static/file/trie.js"></script>

由于已加载此文件,因此您应该有权访问RAW_TRIE对象。您可以将prototype设置为Trie并使用搜索方法:

const TRIE = Object.setPrototypeOf(RAW_TRIE,new Trie());
console.log("hello exists: " + TRIE.search("hello"));
console.log("hello1 does not exist: " + TRIE.search("hello1"));

这种方法允许您在服务器端创建需要的所有单词的文件,客户端可以下载该文件并将其用作常规静态文件。

注意:以上解决方案是实现此目的的唯一方法,可以改进或更改某些(或全部)步骤。它不是最终版本 可以在不改变生产的情况下使用。您可以尝试 对其进行优化,并通过更改来使trie.js文件尽可能小 TrieNode功能,甚至将其删除。

,

在这里,您可以通过扩展原生Map原型来创建Trie:

class TrieNode extends Map {
    add(word) {
        if (!word.length) return super.set("end",true);
        let child = this.get(word[0]);
        if (!child) this.set(word[0],child = new TrieNode);
        child.add(word.slice(1));
        return this; // optional: to allow chaining
    }
    has(word) {
        if (!word.length) return super.has("end");
        let child = this.get(word[0]);
        return !!child && child.has(word.slice(1));
    }
    * [Symbol.iterator]() {
        for (let [letter,child] of super.entries()) {
            if (letter === "end") yield ""
            else for (let word of child) yield letter + word;
        }
    }
}

// Demo
let trie = new TrieNode;
// Insert all words
for (let word of ["so","some","somebody","someone","something","son"]) {
    trie.add(word);
}
// For a series of strings,check whether they are in the Trie
for (let word of Array.from("somethings",(_,i) => "somethings".slice(0,i))) {
    console.log(`"${word}" => ${trie.has(word)}`);
}
// List all words that are in the Trie
for (let word of trie) console.log(word);