Javascript:在前缀树中查找以给定前缀开头的10个单词

Javascript:在前缀树中查找以给定前缀开头的10个单词,javascript,recursion,closures,trie,prefix-tree,Javascript,Recursion,Closures,Trie,Prefix Tree,我有一个trie(也称为前缀树)。给定一个前缀,我想得到一个以前缀开头的十个单词的列表 这个问题的独特之处在于,我只需要10个以给定前缀开头的单词,而不是全部。考虑到这一点,可以进行一些优化 我知道下面的代码工作正常。trie中的每个节点都有一个children属性和一个this\u是\u a\u word属性的\u end\u。例如,当您插入“hi”时,这是trie的外观: 问题是:给定一个前缀,我想得到一个以前缀开头的十个单词的列表 我解决这个问题的方法是:沿着前缀树,跟随prefix的

我有一个trie(也称为前缀树)。给定一个前缀,我想得到一个以前缀开头的十个单词的列表

这个问题的独特之处在于,我只需要10个以给定前缀开头的单词,而不是全部。考虑到这一点,可以进行一些优化

我知道下面的代码工作正常。trie中的每个节点都有一个
children
属性和一个
this\u是\u a\u word
属性的\u end\u。例如,当您插入“hi”时,这是trie的外观:

问题是:给定一个前缀,我想得到一个以前缀开头的十个单词的列表

我解决这个问题的方法是:沿着前缀树,跟随
prefix
的字符,直到到达与
prefix
的最后一个字符对应的节点。现在,您应该在此节点上执行DFS,跟踪在列表中具有
this\u是\u a\u word===true
的\u end\u的节点。但当列表长度等于10时,应停止搜索,并返回列表

我认为我的方法是合理的,但我在实现它时遇到了困难——特别是因为我试图使用递归DFS,所以我不确定如何在递归调用之间传递“全局”列表。我知道我应该使用闭包,但我是javascript新手,不知道如何使用闭包。下面是我已经尝试过的一个例子

我的Trie类(我知道这段代码是有效的,这只是为了让您看到我是如何组织数据结构的。)


基本上,我采用您的模型,并将一个新方法
getWords(word[,count])
应用到
Trie
类。我更改了方法
contains
,因为我还需要
getWords
中的功能。因此,我创建了一个新方法
getNode
,它返回找到单词或部分的节点

方法
getWords
首先查找单词(部分),然后遍历数据结构。当找到一个单词时,它被推送到结果集。如果结果集长度大于或等于所需长度,则迭代(因此
Array.prototype.some
)终止,并停止对
fork
的递归调用

    that.getWords = function (word, count) {

        function fork(n, w) {

            function child(c) {
                return fork(n.children[c], w + c);
            }

            n.isWord && words.push(w);
            return words.length >= count || Object.keys(n.children).some(child);
        }

        var words = [],
            current_node = that.getNode(word);

        if (current_node) {
            fork(current_node, word);
            return words;
        }
    }
旁注:我把
这个单词的结尾改为
isWord

输入

  • 创建
    Trie
    的新实例
  • 插入一些用于测试的单词
  • 输出

  • 测试trie是否包含“电机”
  • ,返回false
  • 测试trie是否包含
    'te'
    ,返回false
  • 测试trie是否包含
    'ten'
    ,返回true
  • 获取所有以
    'ind'
    开头的单词(8可用,显示8)
  • 获取以“”开头的前10个单词(16个可用,显示10个)
  • 整个的黎波里
  • var-Trie=函数(){
    var=Object.create(Trie.prototype);
    that.children={};//映射:下一个字符->子节点
    that.isWord=false;
    that.insertWord=函数(word){
    var current_node=该值;
    for(变量i=0;i=count | | Object.keys(n.children).some(child);
    }
    var words=[],
    当前_节点=该.getNode(word);
    if(当前_节点){
    fork(当前_节点,字);
    返回单词;
    }
    }
    //freeze会锁定isWord属性,这在这里不是必需的
    //反对.冻结(那);
    归还;
    }
    var trie=新的trie();
    插入单词([
    ‘汽车’、‘酷’、‘我’、‘在’、‘事实上’、‘独立’、‘印度’、‘室内’、‘感应’,
    ‘工业’、‘工业’、‘印德维尔’、‘劣等’、‘非正式’、‘吸入’、‘客栈’,
    “内部”、“实例”、“无畏”、“of”、“off”、“其他”、“tea”、“ted”、“ten”,
    “到”、“动物园”、“缩放”
    ]);
    document.write(trie.contains('motor')+“
    ”);//假的 document.write(trie.contains('te')+“
    ”);//假的 document.write(trie.contains('ten')+“
    ”);//真的 document.write(''+JSON.stringify(trie.getWords('ind'),0,4)+''; document.write(“”+JSON.stringify(trie.getWords('in',10),0,4)+“”);
    write(“”+JSON.stringify(trie,0,4)+“”)请看一看谢谢,我看了那篇文章,但它查找了所有以
    num_words_to_go = 10; 
    //this global is bad practice; 
    //I want to put this as the argument to a closure 
    //so it's passed between recursive calls
    
    that.getWords = function(start_node, prefix) {
       console.log(0);
       var words = [];
    
       //if start node is a word, add it
       if (start_node.this_is_the_end_of_a_word) {
           words.push(start_node);
           num_words_to_go--;
       }
    
       if (num_words_to_go <= 0 || !start_node.children) {
           return words;
       }
    
       return start_node.children.forEach(
                                  currentValue.getWords(
                                        currentValue, prefix + <character for this child>)); 
    
       /*I can't think of a nice way to write this without going through all of the children. 
       I know I don't need to, because I only need to find 10 words and get out. 
       This is why I was leaning towards the recursive DFS. 
       */
    
    that.all_suffixes = function (prefix){
        results = [];
        if (that.this_is_the_end_of_a_word) results.push(prefix);
        if (!(that.children)) return results;
        if (results.length > 2) return results;
        var callback = function(currentValue, i, array){
            return currentValue.all_suffixes(prefix+array[i]);
        }
        arr = that.children.forEach(callback, that);
            //[child.all_suffixes(prefix + char) for (char, child) in self.children.items()]
        return concat(reduce(concat, arr), results);        
    }
    
     that.autocomplete = function(prefix){
        current_node = that;
        for(var i = 0; i < prefix.length; i++){
            var c = prefix[i];
            //if there is nothing in the trie with this prefix
            if (!(c in current_node.children)){
                return [];
            }
            current_node = current_node.children[c];
        }
        return list(current_node.all_suffixes(prefix))
     }
    
        that.getWords = function (word, count) {
    
            function fork(n, w) {
    
                function child(c) {
                    return fork(n.children[c], w + c);
                }
    
                n.isWord && words.push(w);
                return words.length >= count || Object.keys(n.children).some(child);
            }
    
            var words = [],
                current_node = that.getNode(word);
    
            if (current_node) {
                fork(current_node, word);
                return words;
            }
        }