Javascript:在前缀树中查找以给定前缀开头的10个单词
我有一个trie(也称为前缀树)。给定一个前缀,我想得到一个以前缀开头的十个单词的列表 这个问题的独特之处在于,我只需要10个以给定前缀开头的单词,而不是全部。考虑到这一点,可以进行一些优化 我知道下面的代码工作正常。trie中的每个节点都有一个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的
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
'te'
,返回false'ten'
,返回true'ind'
开头的单词(8可用,显示8)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;
}
}