/// <summary> /// delete a word from the tree means delete the last leaf that makes up the stored word /// </summary> /// <param name="label"></param> /// <param name="curNode"></param> public void DeleteRec(string wordPart, Node curNode) { var matches = MatchingConsecutiveCharacters(wordPart, curNode); if ((matches == 0) || (curNode == _root) || ((matches > 0) && (matches < wordPart.Length) && (matches >= curNode.Label.Length))) { var newLabel = wordPart.Substring(matches, wordPart.Length - matches); foreach (var child in curNode.SubNodes) if (child.Label.StartsWith(newLabel[0].ToString())) { if (newLabel == child.Label) { if (child.SubNodes.Count == 0) { curNode.SubNodes.Remove(child); return; } } DeleteRec(newLabel, child); } } }
public TrieNode(Node n) { this.n = n; indx = 0; if (n.Label.Length == 0) { c = '$'; } else c = n.Label[indx]; }
public void CreateTree() { tree = Node<string>.Root(); }
public TrieNode(Node n, int indx) { this.n = n; this.indx = indx + 1; c = n.Label[this.indx]; }
/// <summary> /// given a string and a node the number of characters that the string and the node's label have /// in common starting from the first character in each is returned /// </summary> /// <param name="word">a string that is to be compared with the node's label</param> /// <param name="curNode">a node</param> /// <returns></returns> private int MatchingConsecutiveCharacters(string word, Node curNode) { int matches = 0; int minLength = 0; //see which string is smaller and save it's lenght //when cycling throught the two strings we won't go any further than that if (curNode.Label.Length >= word.Length) minLength = word.Length; else if (curNode.Label.Length < word.Length) minLength = curNode.Label.Length; if(minLength > 0) //go throught the two streams for (int i = 0; i < minLength; i++) { //if two characters at the same position have the same value we have one more match if(word[i] == curNode.Label[i]) matches++; else //if at any position the two strings have different characters break the cycle break; } //and return the current number of matches return matches; }
/// <summary> /// look for a word in the tree begining at the current node /// </summary> /// <param name="wordPart"></param> /// <param name="curNode"></param> /// <returns></returns> private bool LookupRec(string wordPart, Node curNode) { var matches = MatchingConsecutiveCharacters(wordPart, curNode); if ((matches == 0) || (curNode == _root) || ((matches > 0) && (matches < wordPart.Length) && (matches >= curNode.Label.Length))) { var newLabel = wordPart.Substring(matches, wordPart.Length - matches); foreach (var child in curNode.SubNodes) if (child.Label.StartsWith(newLabel[0].ToString())) return LookupRec(newLabel, child); return false; } else if (matches == curNode.Label.Length) { return true; } else return false; }
/// <summary> /// construct a new tree with it's root /// </summary> public Tree() { _root = new Node(""); }
/// <summary> /// recursively traverse the tree /// carry the word you want inserted until a proper place for it is found and it can be inserted there /// if a node already stores a substring of the word(substrnig with the same first letter as the word itself) /// then that substring must be removed from the word and it's children checked out next /// hence the name wordPart - part of a word /// </summary> /// <param name="wordPart">the part of the word that is to be inserted that is not already included in any of the tree's nodes</param> /// <param name="curNode">the node currently traversed</param> private void InsertRec(string wordPart, Node curNode) { //get the number of characters that the word part that is to be inserted and the current node's label have //in common starting from the first position of both strings //matching characters in the two strings = have the same value at the same position in both strings var matches = MatchingConsecutiveCharacters(wordPart, curNode); //if we are at the root node //OR //the number of characters from the two strings that match is //bigger than 0 //smaller than the the part of the word that is to be inserted //bigger than the the label of the current node if ((matches == 0) || (curNode == _root) || ((matches > 0) && (matches < wordPart.Length) && (matches >= curNode.Label.Length))) { //remove the current node's label from the word part bool inserted = false; var newWordPart = wordPart.Substring(matches, wordPart.Length - matches); //search the node's subnodes and if the subnode label's first character matches //the word part's first character then insert the word part after this node(call the //current method recursively) foreach(var child in curNode.SubNodes) if (child.Label.StartsWith(newWordPart[0].ToString())) { inserted = true; InsertRec(newWordPart, child); } if (inserted == false) { curNode.SubNodes.Add(new Node(newWordPart)); } } else if(matches < wordPart.Length) { //in this case we have to nodes that we must add to the tree //one is the node that has a label extracted from the current node's label without the string of //matching characters(common characters) //the other is the node that has it's label extracted from the current word part minus the string //of matching characters string commonRoot = wordPart.Substring(0, matches); string branchPreviousLabel = curNode.Label.Substring(matches, curNode.Label.Length - matches); string branchNewLabel = wordPart.Substring(matches, wordPart.Length - matches); curNode.Label = commonRoot; var newNodePreviousLabel = new Node(branchPreviousLabel); newNodePreviousLabel.SubNodes.AddRange(curNode.SubNodes); curNode.SubNodes.Clear(); curNode.SubNodes.Add(newNodePreviousLabel); var newNodeNewLabel = new Node(branchNewLabel); curNode.SubNodes.Add(newNodeNewLabel); } else if (matches == curNode.Label.Length) { //in this case we don't do anything because the word is already added } else if (matches > curNode.Label.Length) { //add the current word part minus the common characters after the current node string newNodeLabel = curNode.Label.Substring(curNode.Label.Length, wordPart.Length); var newNode = new Node(newNodeLabel); curNode.SubNodes.Add(newNode); } }
private string FindSuccessorRec(string wordPart, Node curNode,string carry) { var matches = MatchingConsecutiveCharacters(wordPart, curNode); if ((matches == 0) || (curNode == _root) || ((matches > 0) && (matches < wordPart.Length) )) { var newLabel = wordPart.Substring(matches, wordPart.Length - matches); foreach (var child in curNode.SubNodes) if (child.Label.StartsWith(newLabel[0].ToString())) return FindSuccessorRec(newLabel, child, carry + curNode.Label); return curNode.Label; } else if (matches < curNode.Label.Length) { return carry + curNode.Label; } else if (matches == curNode.Label.Length) { carry = carry + curNode.Label; int min = int.MaxValue; int index = -1; for (int i = 0; i < curNode.SubNodes.Count;i++ ) if (curNode.SubNodes[i].Label.Length < min) { min = curNode.SubNodes[i].Label.Length; index = i; } if (index > -1) return carry + curNode.SubNodes[index].Label; else return carry; } else return string.Empty; }
/// <summary> /// </summary> /// <param name="wordPart"></param> /// <param name="curNode"></param> /// <returns></returns> private string FindPredecessorRec(string wordPart, Node curNode,string carry) { var matches = MatchingConsecutiveCharacters(wordPart, curNode); if ((matches == 0) || (curNode == _root) || ((matches > 0) && (matches < wordPart.Length) && (matches >= curNode.Label.Length))) { var newLabel = wordPart.Substring(matches, wordPart.Length - matches); foreach (var child in curNode.SubNodes) if (child.Label.StartsWith(newLabel[0].ToString())) return FindPredecessorRec(newLabel, child, carry + curNode.Label); return carry + curNode.Label; } else if (matches == curNode.Label.Length) { return carry + curNode.Label; } else return string.Empty; }