I have a trie (also called a prefix tree). Given a prefix, I want to get a list of ten words that start with the prefix.
Basically I take your model and apply a new method getWords(word[, count]) to the Trie class. I changed the method contains because I need the functionality in getWords as well. So I created a new method getNode, which returns the node where the word or part is found.
The method getWords first looks up the word (part) and then iterates through the data structure. When a word is found it is pushed to the result set. If the result set length is greater or equal to the required length, then the iteration (hence Array.prototype.some) is terminated and the recursive call of fork is stopped.
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;
}
}
Side note: I changed this_is_the_end_of_a_word to isWord.
Input
Trie.Output
'motor', returns false.'te', returns false.'ten', returns true.'ind' (8 available, shows 8).'in' (16 available, shows 10).var Trie = function () {
var that = Object.create(Trie.prototype);
that.children = {}; //mapping: next character -> child nodes
that.isWord = false;
that.insertWord = function (word) {
var current_node = that;
for (var i = 0; i < word.length; i++) {
var c = word[i]
//if character is not in the trie already, add it
if (!(c in current_node.children)) {
current_node.children[c] = Trie();
}
//update current_node
current_node = current_node.children[c];
};
//after adding all the chars of the word,
//you are at the end of a word
current_node.isWord = true;
}
that.insertWords = function (words) {
for (var i = 0; i < words.length; i++) {
that.insertWord(words[i]);
}
}
that.getNode = function (word) {
//start at the root
var current_node = that;
for (var i = 0; i < word.length; i++) {
var c = word[i];
//if the word's character isn't a child of the current_node,
//the word isn't in the trie
if (!(c in current_node.children)) {
return;
}
//move down the trie, update current_node
current_node = current_node.children[c];
};
return current_node;
}
that.contains = function (word) {
var current_node = that.getNode(word);
if (current_node) {
return current_node.isWord;
}
return false;
}
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;
}
}
// freeze does lock the isWord property, which is not required here
//Object.freeze(that);
return that;
}
var trie = new Trie();
trie.insertWords([
'car', 'cool', 'i', 'in', 'indeed', 'independence', 'india', 'indoor', 'induction',
'industrial', 'industry', 'indwell', 'inferior', 'informal', 'inhale', 'inn',
'inside', 'instance', 'intrepid', 'of', 'off', 'other', 'tea', 'ted', 'ten',
'to', 'zoo', 'zoom'
]);
document.write(trie.contains('motor') + '<br>'); // false
document.write(trie.contains('te') + '<br>'); // false
document.write(trie.contains('ten') + '<br>'); // true
document.write('<pre>' + JSON.stringify(trie.getWords('ind'), 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(trie.getWords('in', 10), 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(trie, 0, 4) + '</pre>');