/// <summary> /// Adds the specified term into the Radix. /// </summary> /// <param name="term">The term.</param> public void Add(string term) { if (term == null) { throw new ArgumentNullException("term"); } RadixNode node = head; // Adding control char var prefixChars = new List <char>(term) { new char() }; foreach (char prefixChar in prefixChars) { var child = node.GetChild(prefixChar); if (child == null) { child = new RadixNode(prefixChar); node.AddChild(child); } node = child; } }
/// <summary> /// Finds the specified prefix. /// </summary> /// <param name="prefix">The prefix.</param> /// <returns></returns> public IEnumerable <string> Find(string prefix) { if (prefix == null) { throw new ArgumentNullException("prefix"); } StringBuilder.Clear(); RadixNode node = head; foreach (char prefixChar in prefix) { var child = node.GetChild(prefixChar); node = child; if (child == null) { return(new string[0]); } StringBuilder.Append(prefixChar); } return(node.GetChildsTerms(StringBuilder.ToString())); }
void enum_objects(ArrayList o, RadixNode n) { if (n.Object != null) { o.Add(n.Object); } foreach (RadixNode nc in n.SubNodes) { enum_objects(o, nc); } }
/// <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 RadixNode?LookupRec(byte[] word, int pos, RadixNode curNode) { int matches = MatchingConsecutiveCharacters(word, pos, curNode); if ((matches == 0) || (curNode == Root) || ((matches > 0) && (matches < (word.Length - pos)) && (matches >= curNode.Label.Length))) { RadixNode?ret = null; int new_pos = pos + matches; foreach (RadixNode child in curNode.SubNodes) { if (child.Label[0] == word[new_pos]) { ret = LookupRec(word, new_pos, child); if (ret != null) { break; } } } if (ret == null) { ret = curNode; } return(ret); } else if (matches == curNode.Label.Length) { return(curNode); } else { return(null); } }
/// <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(byte[] word, int word_pos, RadixNode 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 - word_pos)) { minLength = word.Length - word_pos; } else if (curNode.Label.Length < (word.Length - word_pos)) { 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 + word_pos] == 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> /// Adds the child node into the current RadixNode lookup table. /// </summary> /// <param name="node">The node.</param> public void AddChild(RadixNode node) { radixNodes.Add(node.Char, node); }
/// <summary> /// Initializes a new instance of the <see cref="Radix"/> class. /// </summary> public Radix() { head = new RadixNode(); }
/// <summary> /// Performs a sort of the specified <c>collection</c> in O(n). /// </summary> /// <param name="collection"></param> /// <param name="noOfBaskets">Indicates how many baskets should be used for partitioning the items in the collection.</param> public static void RadixSort(IList <int> collection, int noOfBaskets) { // Create the queues that will be used for storing the partitioned data: var queues = new Queue <RadixNode> [noOfBaskets]; for (int i = 0; i < noOfBaskets; i++) { queues[i] = new Queue <RadixNode>(); } // Add all the items in the collection to a queue: (The 1st queue has been chosen arbitrarilly.) // Perform validation of input at the same time. for (int i = 0; i < collection.Count; i++) { if (collection[i] < 0) { throw new NotImplementedException("Negative numbers are not supported by this Radix sort implementation."); } string text = collection[i].ToString(); queues[0].Enqueue(new RadixNode(collection[i])); } // Remember that all the items are in the first queue. int[] itemsInQueue_old = new int[noOfBaskets]; itemsInQueue_old[0] = collection.Count; // Start the iterative part, ... bool isContinuing = true; while (isContinuing) { isContinuing = false; int[] itemsInQueue_new = new int[noOfBaskets]; // Go through all the queues: for (int i = 0; i < queues.Length; i++) { // Process all the items in this queue: // (Bear in mind that additional items may be placed in this queue as it is recycled for this iteration.) for (int j = 0; j < itemsInQueue_old[i]; j++) { RadixNode node = queues[i].Dequeue(); int basket = node.RemainingValue % noOfBaskets; node.RemainingValue = node.RemainingValue / noOfBaskets; if (node.RemainingValue != 0) { isContinuing = true; } queues[basket].Enqueue(node); itemsInQueue_new[basket]++; } } itemsInQueue_old = itemsInQueue_new; } // Return the result: int r_i = 0; // For each queue in the collection of queues, ... for (int i = 0; i < queues.Length; i++) { // Add the items to the final results. while (queues[i].Count > 0) { collection[r_i++] = queues[i].Dequeue().OriginalValue; } } }
/// <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 RadixNode?InsertRec(byte[] wordPart, RadixNode curNode) { RadixNode?ret = null; //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 int matches = MatchingConsecutiveCharacters(wordPart, 0, 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; byte[] newWordPart = Util.CopyByte(wordPart, 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 (RadixNode child in curNode.SubNodes) { if (child.Label[0] == newWordPart[0]) { inserted = true; ret = InsertRec(newWordPart, child); } } if (inserted == false) { ret = new RadixNode(curNode, newWordPart); curNode.SubNodes.Add(ret); this.Count++; } } 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 byte[] commonRoot = Util.CopyByte(wordPart, 0, matches); byte[] branchPreviousLabel = Util.CopyByte(curNode.Label, matches); byte[] branchNewLabel = Util.CopyByte(wordPart, matches); curNode.Label = commonRoot; RadixNode newNodePreviousLabel = new RadixNode(curNode, branchPreviousLabel); newNodePreviousLabel.Object = curNode.Object; newNodePreviousLabel.SubNodes.AddRange(curNode.SubNodes); foreach (RadixNode n in curNode.SubNodes) { n.Parent = newNodePreviousLabel; } curNode.SubNodes.Clear(); curNode.SubNodes.Add(newNodePreviousLabel); curNode.Object = null; RadixNode newNodeNewLabel = new RadixNode(curNode, branchNewLabel); curNode.SubNodes.Add(newNodeNewLabel); ret = newNodeNewLabel; this.Count++; } 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 byte[] newNodeLabel = Util.CopyByte(curNode.Label, curNode.Label.Length, wordPart.Length); RadixNode newNode = new RadixNode(curNode, newNodeLabel); curNode.SubNodes.Add(newNode); ret = newNode; this.Count++; } return(ret); }
public RadixTrie(RadixNode root) { Root = root; }
/// <summary> /// construct a new tree with it's root /// </summary> public RadixTrie() { Root = new RadixNode(null, new byte[0]); }