/// <summary> /// Recursive function that dDetermines whether the tree contains the specified word. /// </summary> /// <param name="chars">The chars.</param> /// <param name="position">The position.</param> /// <param name="node">The node.</param> /// <returns> /// <c>true</c> if the tree contains the specified word; otherwise, <c>false</c>. /// </returns> private bool Contains(char[] chars, int position, TernaryTreeNode node) { if (node == null) { return(false); } char currentChar = chars[position]; if (node.CurrentChar == currentChar) { if (position + 1 == chars.Length) { if (node.CurrentObject != null) { return(true); } return(false); } return(Contains(chars, position + 1, node.Middle)); } else if (node.CurrentChar < currentChar) { return(Contains(chars, position, node.Right)); } else { return(Contains(chars, position, node.Left)); } }
public void Delete(string key) { var current = root; var index = 0; var previousIndex = 0; TernaryTreeNode <char, T> previousKey = root; while (current != null && index < key.Length) { if (!current.Value.Equals(default(T))) { previousIndex = index; previousKey = current; } var comparisonResult = key[index].CompareTo(current.Key); if (comparisonResult < 0) { current = current.LeftChild; } else if (comparisonResult > 0) { current = current.RightChild; } else { if (index == key.Length - 1) { if (!current.Value.Equals(default(T))) { Size--; if (current.LeftChild == null && current.MiddleChild == null && current.RightChild == null) { if (key[previousIndex].CompareTo(previousKey.Key) < 0) { previousKey.LeftChild = null; } else if (key[previousIndex].CompareTo(previousKey.Key) > 0) { previousKey.RightChild = null; } else { previousKey.MiddleChild = null; } } else { current.Value = default(T); } } } else { current = current.MiddleChild; index++; } } } }
private TernaryTreeNode <char, T> Put(string key, T value, int index, TernaryTreeNode <char, T> node) { if (node == null) { node = new TernaryTreeNode <char, T>(key[index]); } var comparisonResult = key[index].CompareTo(node.Key); if (comparisonResult < 0) { node.LeftChild = Put(key, value, index, node.LeftChild); } else if (comparisonResult > 0) { node.RightChild = Put(key, value, index, node.RightChild); } else { if (index == key.Length - 1) { node.Value = value; Size++; } else { node.MiddleChild = Put(key, value, index + 1, node.MiddleChild); } } return(node); }
/// <summary> /// Prepares for search. /// </summary> public void PrepareForSearch() { // Initialize the root Root = new TernaryTreeNode(); // Sort the array List <string> keys = new List <string>(words.Keys.ToArray <string>()); keys.Sort(StringComparer.InvariantCultureIgnoreCase); // Start filling the tree starting from the middle until all the elements are in. It should give good balancing DichotomicTraversal(keys, 0, words.Count - 1); IsPreparedForSearch = true; }
/// <summary> /// Composes the match list. /// </summary> /// <param name="node">The current node.</param> /// <param name="result">The result that contains all the words.</param> /// <returns></returns> private List <T> ComposeMatchList(TernaryTreeNode node, List <T> result) { if (node.CurrentObject != null) { result.Add(node.CurrentObject); } if (node.Left != null) { result = ComposeMatchList(node.Left, result); } if (node.Middle != null) { result = ComposeMatchList(node.Middle, result); } if (node.Right != null) { result = ComposeMatchList(node.Right, result); } return(result); }
private IEnumerable <string> GetKeys(TernaryTreeNode <char, T> node) { if (node == null) { throw new InvalidOperationException(); } var queue = new Queue <Tuple <TernaryTreeNode <char, T>, StringBuilder> >(); queue.Enqueue(new Tuple <TernaryTreeNode <char, T>, StringBuilder>(node, new StringBuilder(node.Key.ToString()))); while (queue.Count > 0) { var item = queue.Dequeue(); var current = item.Item1; var key = item.Item2; if (!current.Value.Equals(default(T))) { yield return(key.ToString()); } if (current.LeftChild != null) { queue.Enqueue(new Tuple <TernaryTreeNode <char, T>, StringBuilder>(current.LeftChild, new StringBuilder(key.ToString()))); } if (current.MiddleChild != null) { queue.Enqueue(new Tuple <TernaryTreeNode <char, T>, StringBuilder>(current.MiddleChild, new StringBuilder(key.Append(current.MiddleChild.Key).ToString()))); } if (current.RightChild != null) { queue.Enqueue(new Tuple <TernaryTreeNode <char, T>, StringBuilder>(current.RightChild, new StringBuilder(key.ToString()))); } } }
/// <summary> /// Finds the start node for matching. /// </summary> /// <param name="chars">The array of chars.</param> /// <param name="position">The current position.</param> /// <param name="node">The current node.</param> /// <returns></returns> private TernaryTreeNode FindStartNode(char[] chars, int position, TernaryTreeNode node) { if (position == chars.Length) { return(node); } char currentChar = chars[position]; if (currentChar == node.CurrentChar) { return(FindStartNode(chars, position + 1, node.Middle)); } else if (node.CurrentChar < currentChar) { return(FindStartNode(chars, position, node.Right)); } else { return(FindStartNode(chars, position, node.Left)); } }
/// <summary> /// Find matches witht the given prefix. /// </summary> /// <param name="prefix">The prefix. Can be empty - all words from the tree are returned in this case.</param> /// <returns></returns> public IList <T> Matches(string prefix) { if (!IsPreparedForSearch) { throw new InvalidOperationException("The tree has to be prepared before searching."); } var result = new List <T>(); // Step 1 - find the node node string prefixNormilized = string.Empty; if (!string.IsNullOrEmpty(prefix)) { prefixNormilized = prefix.ToLowerInvariant(); } TernaryTreeNode start = FindStartNode(prefixNormilized.ToCharArray(), 0, Root); // Step 2 - get all words starting from the node node result = ComposeMatchList(start, result); return(result); }
/// <summary> /// Stores the word in the tree. /// </summary> /// <param name="word">The word.</param> /// <param name="chars">The array of characters (must be in lower case).</param> /// <param name="position">The position.</param> /// <param name="currentChar">The current char.</param> /// <param name="node">The node.</param> private void StoreWordInTree(string word, char[] chars, int position, char currentChar, TernaryTreeNode node) { if (node.CurrentChar == 0) { Debug.Assert(node.Middle == null); node.CurrentChar = currentChar; node.Middle = new TernaryTreeNode(); if (position + 1 == chars.Length) { Debug.Assert(node.CurrentObject == null); node.CurrentObject = words[word]; return; } StoreWordInTree(word, chars, position + 1, chars[position + 1], node.Middle); } else if (node.CurrentChar == currentChar) { Debug.Assert(node.Middle != null); if (position + 1 == chars.Length) { Debug.Assert(node.CurrentObject == null); node.CurrentObject = words[word]; return; } StoreWordInTree(word, chars, position + 1, chars[position + 1], node.Middle); } else if (node.CurrentChar > currentChar) { if (node.Left == null) { node.Left = new TernaryTreeNode(); } StoreWordInTree(word, chars, position, chars[position], node.Left); } else { if (node.Right == null) { node.Right = new TernaryTreeNode(); } StoreWordInTree(word, chars, position, chars[position], node.Right); } }
public void Put(string key, T value) { root = Put(key, value, 0, root); }