/// <summary> /// Returns an enumerator that iterates through the collection. /// </summary> /// <returns> /// A <see cref="IEnumerator{T}"/>that can be used to iterate through the /// collection. /// </returns> public IEnumerator <KeyValuePair <TKey, TValue> > GetEnumerator() { if (root_.Level != 0) { Stack <AndersonTreeNode <TKey, TValue> > stack = new Stack <AndersonTreeNode <TKey, TValue> >(); stack.Push(root_); while (stack.Count > 0) { AndersonTreeNode <TKey, TValue> node = stack.Pop(); KeyValuePair <TKey, TValue> key_value_pair = new KeyValuePair <TKey, TValue>(node.Key, node.Value); yield return(key_value_pair); if (node.Left.Level != 0) { stack.Push(node.Left); } if (node.Right.Level != 0) { stack.Push(node.Right); } } } }
/// <summary> /// Initializes a new instance of the /// <see cref="AndersonTreeNode{TKey,TValue}"/> by using the specified key, /// value and sentinel node. /// </summary> /// <param name="key">The key of the node</param> /// <param name="value">The value of the node</param> /// <param name="sentinel">The sentinel node</param> public AndersonTreeNode(TKey key, TValue value, AndersonTreeNode <TKey, TValue> sentinel) { childs = new AndersonTreeNode <TKey, TValue> [2]; childs[0] = sentinel; childs[1] = sentinel; key_ = key; value_ = value; level_ = 1; }
/// <summary> /// Determines whether the <see cref="AndersonTree<TKey,TValue>"/> /// constains and element with the specified key. /// </summary> /// <param name="key">The key to locate in the /// <see cref="AndersonTree<TKey,TValue>"/></param> /// <returns>true if the <see cref="AndersonTree<TKey,TValue>"/> /// constains an element with the key; otherwise, false</returns> /// <exception cref="ArgumentNullException">key is null</exception> public bool ContainsKey(TKey key) { AndersonTreeNode <TKey, TValue> node = FindNode(key); if (node.Level == 0) { return(false); } return(true); }
/// <summary> /// Determines whether a value is in the /// <see cref="AndersonTree{TKey,TValue}"/> /// </summary> /// <param name="key_value_pair"> /// The value to locate in the <see cref="AndersonTree{TKey,TValue}"/> /// </param> /// <returns> /// <c>true</c> if the item is found in the /// <see cref="AndersonTree{TKey,TValue}"/> /// </returns> public bool Contains(KeyValuePair <TKey, TValue> key_value_pair) { AndersonTreeNode <TKey, TValue> node = FindNode(key_value_pair.Key); if (node.Level != 0) { EqualityComparer <TValue> comparer = EqualityComparer <TValue> .Default; return(comparer.Equals(key_value_pair.Value, node.Value)); } return(false); }
/// <summary> /// Gets or sets the value associated with the specified key /// </summary> /// <param name="key"> /// The key whose value to get or set. /// </param> /// <returns> /// The value associated with the specified key. If the specified key is /// not found, attempting to get it throws a /// <see cref="KeyNotFoundException"/>, and attempting to set it creates a /// new element with the specified key. /// </returns> /// <exception cref="ArgumentNullException"> /// key is <c>null</c>. /// </exception> /// <exception cref="KeyNotFoundException"> /// The key does not exists in the tree. /// </exception> public TValue this[TKey key] { get { AndersonTreeNode <TKey, TValue> node = FindNode(key); if (node.Level == 0) { throw new KeyNotFoundException("key"); } return(node.Value); } set { Insert(key, value, false); } }
/// <summary> /// Gets the value associated with the specified key. /// </summary> /// <param name="key">The key of the value to get</param> /// <param name="value">When this method returns, contain the value /// associated with the specified key, if the is found; otherwise, the /// default value for the type of the <paramref name="value"/> parameter. /// This parameter is passed uninitialized</param> /// <returns>true if the AndersonTree contains an element with the /// specified key; otherwise, false</returns> public bool TryGetValue(TKey key, out TValue value) { AndersonTreeNode <TKey, TValue> node = FindNode(key); if (node.Level == 0) { value = default(TValue); return(false); } value = node.Value; return(true); }
/// <summary> /// Performs a skew operation over a node. /// </summary> /// <param name="node">the node to skew</param> /// <remarks>Skew is a right rotation when an insertion or deletion creates /// a left horizontal link. No changes are needed to the levels after a /// skew because the operation simply turns a left horizontal link into a /// right horizontal link.</remarks> internal void Skew(ref AndersonTreeNode <TKey, TValue> node) { // non-sentinel_ node with a horizontal link if (node.Level != 0 && node.Left.Level == node.Level) { // remove the horizontal link by rotating right AndersonTreeNode <TKey, TValue> save = node.Left; node.Left = save.Right; save.Right = node; node = save; } }
/// <summary> /// Performs a split operation over a node. /// </summary> /// <param name="node">The node to split</param> /// Split performs a left rotation operation on a node when an inserion /// or deletion creates a consecutive horizontal links. internal void Split(ref AndersonTreeNode <TKey, TValue> node) { // non-sentinel_ node with a consecutive horizontal link if (node.Level != 0 && node.Right.Right.Level == node.Level) { // remove the horizontal link by rotating left and increasing the node // level AndersonTreeNode <TKey, TValue> save = node.Right; node.Right = save.Left; save.Left = node; node = save; ++node.Level; } }
/// <summary> /// Retrieves a <see cref="AndersonTreeNode{TKey,TValue}"/> object in the /// <see cref="AndersonTree{TKey,TValue}"/> associated with the specified key. /// </summary> /// <param name="key">The key of the node to search for</param> /// <returns>The AndersonTreeNode associated with the specified key, if the /// key is found; otherwise an AndersonTreeNode with level zero - sentinel_ /// node.</returns> /// <exception cref="ArgumentNullException">key is null</exception> internal AndersonTreeNode <TKey, TValue> FindNode(TKey key) { int cmp; for (AndersonTreeNode <TKey, TValue> node = root_; node.Level != 0; node = (cmp < 0) ? node.Left : node.Right) { cmp = comparer_.Compare(key, node.Key); if (cmp == 0) { return(node); } } return(sentinel_); }
/// <summary> /// Initializes a new empty <see cref="AndersonTree{TKey,TValue}"/> /// class. /// </summary> /// <param name="comparer"> /// The comparer to use when comparing items. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="comparer"/> is <c>null</c>. /// </exception> public AndersonTree(IComparer <TKey> comparer) { if (comparer == null) { Thrower.ThrowArgumentNullException(ExceptionArgument.comparer); } sentinel_ = new AndersonTreeNode <TKey, TValue>(); sentinel_.Level = 0; sentinel_.Right = sentinel_; sentinel_.Left = sentinel_; root_ = sentinel_; count_ = 0; comparer_ = comparer; key_is_value_type_ = typeof(TKey).IsValueType; }
/// <summary> /// Performs reverse in-order traversal on the /// <see cref="AndersonTree{TKey,TValue}"/> /// </summary> /// <param name="action"> /// A method used to perform some action with each node in the tree. /// </param> /// <remarks> /// The <paramref name="action"/> must return <c>true</c> in order to /// allows the traversal to continue. /// </remarks> internal bool ReverseInOrderTreeWalk(TreeWalkAction <TKey, TValue> action) { if (root_.Level != 0) { Stack <AndersonTreeNode <TKey, TValue> > stack = new Stack <AndersonTreeNode <TKey, TValue> > (2 * ((int)Math.Log((double)(count_ + 1)))); AndersonTreeNode <TKey, TValue> node = root_; // traverse the left branch of the tree until reach a sentinel_ node. while (node.Level != 0) { stack.Push(node); node = node.Right; } while (stack.Count != 0) { node = stack.Pop(); if (!action(node)) { return(false); } // traverse the right branch of the current node and store then into // the execution stack. for (AndersonTreeNode <TKey, TValue> node2 = node.Left; node2.Level != 0; node2 = node2.Right) { stack.Push(node2); } } } return(true); }
/// <summary> /// Removes the element with the specified <paramref name="key"/> from the /// <see cref="AndersonTree<TKey, TValue>"/> /// </summary> /// <param name="key"> /// The key of the element to remove. /// </param> /// <returns> /// <c>true</c> if the element is successfully removed; otherwise, /// <c>false</c>. This method also returns <c>false</c> if key was not /// found in the tree. /// </returns> public bool Remove(TKey key) { int top = 0, direction = 0; AndersonTreeNode <TKey, TValue> node = root_; List <AndersonTreeNode <TKey, TValue> > path = new List <AndersonTreeNode <TKey, TValue> >(count_); // Find node to remove and save path while (true) { path.Add(node); // the key was not found if (node.Level == 0) { return(false); } int cmp = comparer_.Compare(key, node.Key); if (cmp == 0) { break; } direction = (cmp < 0) ? 0 : 1; node = node.childs[direction]; } AndersonTreeNode <TKey, TValue>[] childs = node.childs; top = path.Count; // If the node was found, remove it. if (childs[0] == sentinel_ || childs[1] == sentinel_) { // Single child case int dir2 = (childs[0] == sentinel_) ? 1 : 0; // Unlink the item if (--top != 0) { path[top - 1].childs[direction] = childs[dir2]; } else { // The (--top) expression will be zero when the node // that will be removed is the root node. Since, a horizontal // left link is not allowed, the non-sentinel node will never be // the left node - in single child case only. // // If a node with a key less than the root key is inserted into // the tree a left horizontal link will be created and the split // operation will rotate the tree left on the rebalance. root_ = node.Right; } } else { // Two child case AndersonTreeNode <TKey, TValue> heir = node.Right; AndersonTreeNode <TKey, TValue> prev = node; while (heir.Left != sentinel_) { prev = heir; path.Add(prev); heir = heir.Left; } // clone the node node.Value = heir.Value; node.Key = heir.Key; prev.childs[(prev == node) ? 1 : 0] = heir.Right; } // Walk back and rebalance while (--top >= 0) { node = path[top]; // Which child? if (top != 0) { direction = path[top - 1].Right == node ? 1 : 0; } if (node.Left.Level < node.Level - 1 || node.Right.Level < node.Level - 1) { if (node.Right.Level > --node.Level) { node.Right.Level = node.Level; } // Order is important! Skew(ref node); Skew(ref node.childs[1]); Skew(ref node.childs[1].childs[1]); Split(ref node); Split(ref node.childs[1]); } // Fix the parent if (top != 0) { path[top - 1].childs[direction] = node; } else { root_ = node; } } count_--; return(true); }
/// <summary> /// Inserts an item to the AndersonTree /// </summary> /// <param name="key"> /// The key of the value to insert into the tree. /// </param> /// <param name="value"> /// The value to insert in the tree. /// </param> /// <param name="add"> /// A value indicating when the item will be added or modified. /// </param> void Insert(TKey key, TValue value, bool add) { if (!key_is_value_type_ && key == null) { Thrower.ThrowArgumentNullException(ExceptionArgument.key); } // empty tree if (root_.Level == 0) { root_ = new AndersonTreeNode <TKey, TValue>(key, value, sentinel_); count_++; return; } int cmp, dir; List <AndersonTreeNode <TKey, TValue> > path = new List <AndersonTreeNode <TKey, TValue> >(count_); AndersonTreeNode <TKey, TValue> node = root_; // Find the place to insert the item // - If the item is found and we trying to add a new one, // throw an exception - no duplicate items allowed. // - If a leaf is reached, insert the item in the correct place. // - Else, traverse the tree further. while (true) { path.Add(node); cmp = comparer_.Compare(key, node.Key); if (cmp == 0) { if (add) { Thrower.ThrowArgumentException( ExceptionResource.Argument_AddingDuplicate); } if (node.Level != 0) { node.Value = value; } return; } dir = (cmp < 0) ? 0 : 1; if (node.childs[dir].Level == 0) { break; } node = node.childs[dir]; } // create the new node node.childs[dir] = new AndersonTreeNode <TKey, TValue>(key, value, sentinel_); // Walk back and rebalance int top = path.Count; while (--top >= 0) { AndersonTreeNode <TKey, TValue> n = path[top]; // which child ? if (top != 0) { dir = (path[top - 1].Right == n) ? 1 : 0; } Skew(ref n); Split(ref n); // Fix the parent if (top != 0) { path[top - 1].childs[dir] = n; } else { root_ = n; } } count_++; }
/// <summary> /// Removes all items from the /// <see cref="AndersonTree{TKey,TValue}"/> /// </summary> public void Clear() { root_ = sentinel_; count_ = 0; }