public PrefixTree(int maxDepth, string[] words, bool buildSuffix = false) { this.maxDepth = maxDepth + 1; // +1 because root is a "useless" node root = new PrefixTreeNode(' '); ConstructPrefixTree(words, buildSuffix); }
private bool FindCombinationFromWord(string word, PrefixTreeNode root) { Stack <int> searchStringIdx = new Stack <int>(); searchStringIdx.Push(0); while (searchStringIdx.Count > 0) { int idx = searchStringIdx.Pop(); // Start traversing the PrefixTree until we find a word terminator node. PrefixTreeNode curr = root; int charIdx = idx; while (curr != null && charIdx < word.Length) { if (curr.terminatesWord) { // We've found a word, so we should try searching again for // the word ignoring the first charIdx chars in front. // Unless we've also reached the end of the word... if (charIdx != word.Length) { searchStringIdx.Push(charIdx); } } // In either case, keep searching down until we reach a leaf node // (or cannot progress further). curr = curr.children.ContainsKey(word[charIdx]) ? curr.children[word[charIdx]] : null; // If curr isn't null we'll continue searching at the next charIdx. if (curr != null) { charIdx++; } } // Did we reach a leaf node? if (charIdx == word.Length) { // Was this at least the second traversal for this word? // (This implies we've used two words to form this larger word) if (idx > 0) { // Then we found a match! return(true); } } } return(false); }
/// <summary> /// Build a tree from a list of words /// </summary> /// <param name="wordlist"></param> public void BuildTree(IEnumerable<string> wordlist) { // for each word in the list PrefixTreeNode child; foreach (var word in wordlist) { // if we don't have a child with the first character in the word, create one if (!children.TryGetValue(word[0], out child)) { child = new PrefixTreeNode(word[0]); children.Add(word[0], child); } // insert the word, starting with the child child.InsertWord(word, 0); } }
public IList <string> FindAllConcatenatedWordsInADict(string[] words) { List <string> results = new List <string>(); if (words == null || words.Length == 0 || words.Length == 1) { return(results); } // First store every word into the prefix tree. PrefixTreeNode root = new PrefixTreeNode(); int minStringLen = int.MaxValue; for (int i = 0; i < words.Length; i++) { root.AddWord(0, words[i]); // As an optimization, we'll store the minimum string length // that we see. This way, we know we only need to later test // against strings that are twice this size at minimum. minStringLen = Math.Min(minStringLen, words[i].Length); } minStringLen *= 2; // Now, what we want to do is consider a specialized PrefixTreeTraversal // of each string that meets out minStringLen requirements. foreach (string word in words) { if (word.Length < minStringLen) { continue; } bool found = FindCombinationFromWord(word, root); if (found) { results.Add(word); } } return(results); }
static SyntaxToken() { OperatorsTree = new PrefixTreeNode(); foreach (var op in ValidOperators) { var node = OperatorsTree; foreach (var letter in op) { PrefixTreeNode nextNode; if (node.Nodes.TryGetValue(letter, out nextNode)) node = nextNode; else { nextNode = new PrefixTreeNode(); node.Nodes.Add(letter, nextNode); node = nextNode; } } } }