//----------------------------------------------------------------------------- // // Copyright (c) 2010 Nesterovsky Bros. All rights reserved. // // // An immutable AVL tree imlementation. // //----------------------------------------------------------------------------- namespace NesterovskyBros.Collections.AVL { using System; using System.Collections.Generic; using System.Runtime.Serialization; using System.Security.Permissions; /// /// An AVL tree (self-balancing binary search tree). /// Lookup, insertion, and deletion all take O(log n) time in both /// the average and worst cases. Additions and deletions may require /// the tree to be rebalanced by one or more tree rotations. /// /// The AVL tree is named after its two inventors, G.M. Adelson-Velsky and /// E.M. Landis, who published it in their 1962 paper /// "An algorithm for the organization of information." /// /// Note that tree nodes are immutable and thread safe. /// Position in a tree is defined by a tree navigator, which is mutable and /// not safe for threading. /// /// A node value type. [Serializable] public class TreeNavigator: ICloneable, ICollection, IList, ISerializable { /// /// An immutable AVL tree node. /// /// A node value type. public class Node { /// /// Creates a node instance. /// /// A node value. public Node(V value) { Size = 1; Left = null; Right = null; Value = value; } /// /// Creates a node instance. /// /// A left child. /// A right child. /// A node value. public Node(Node left, Node right, V value) { Size = (left != null ? left.Size : 0) + (right != null ? right.Size : 0) + 1; Left = left; Right = right; Value = value; } /// /// Creates a node instance. /// /// A left child. /// A right child. /// A base node. public Node(Node left, Node right, Node that) { Size = (left != null ? left.Size : 0) + (right != null ? right.Size : 0) + 1; Left = left; Right = right; Value = that.Value; } /// /// A left child node. /// public readonly Node Left; /// /// A right child node. /// public readonly Node Right; /// /// A size of subtree, including this node. /// public readonly int Size; /// /// A node value. /// public readonly V Value; } /// /// Creates a tree navigator instance. /// public TreeNavigator() { } /// /// Creates a copy of a tree navigator instance. /// /// An instance to copy. public TreeNavigator(TreeNavigator that) { if ((that != null) && !(that.depth == 0)) { int depth = that.depth; var path = ReserveDepth(depth); var thatPath = that.path; this.depth = depth; for(int i = 0; i < path.Length; ++i) { if (i >= depth) { break; } path[i] = thatPath[i]; } current = that.current; } } /// /// Creates a tree navigator instance. /// /// A node. public TreeNavigator(Node node) { if (node != null) { current = node; var path = ReserveDepth(1); depth = 1; path[0] = node; } } /// /// Creates a clone of this map. /// /// A serialization info. /// A streaming context. protected TreeNavigator(SerializationInfo info, StreamingContext context): this(Create((V[])info.GetValue("Items", typeof(V[])))) { } #region ICloneable Members /// /// Creates a clone of this tree navigator. /// /// A clone of this tree navigator. public TreeNavigator Clone() { return new TreeNavigator(this); } /// /// Creates a clone of this tree navigator. /// /// A clone of this tree navigator. object ICloneable.Clone() { return Clone(); } #endregion #region ISerializable Members /// /// Populates a SerializationInfo with the data needed to serialize /// the target object. /// /// A SerializationInfo to populate with data. /// A destination for this serialization. [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] void ISerializable.GetObjectData( SerializationInfo info, StreamingContext context) { V[] items = null; if (Count > 0) { items = new V[Count]; CopyTo(items, 0); } info.AddValue("Items", items); } #endregion /// /// Gets node depth. /// public int Depth { get { return depth; } } /// /// Get a root node. /// public Node Root { get { return depth <= 1 ? current : path[0]; } } /// /// Gets a current node. /// public Node Current { get { return current; } } /// /// Gets index of the current node in the tree. /// public int Index { get { int index; if (depth == 0) { index = -1; } else { var path = this.path; Node parent = path[0]; Node left; index = 0; for(int i = 1; i < depth; ++i) { Node node = path[i]; if (parent.Right == node) { ++index; left = parent.Left; if (left != null) { index += left.Size; } } parent = node; } left = parent.Left; if (left != null) { index += left.Size; } } return index; } } /// /// Indicates whether the current node is null. /// public bool IsNull { get { return depth == 0; } } /// /// Indicates whether the current node is root of the tree. /// public bool IsRoot { get { return depth == 1; } } /// /// Indicates whether there is a parent node for the current node. /// public bool HasParent { get { return depth > 1; } } /// /// Indicates whether there is a left child over the current node. /// public bool HasLeft { get { return (current != null) && (current.Left != null); } } /// /// Indicates whether there is a right child over the current node. /// public bool HasRight { get { return (current != null) && (current.Right != null); } } /// /// Indicates whether there is a predecessor node for a current node. /// public bool HasPredecessor { get { bool succeeds = false; if (depth != 0) { var path = this.path; Node child = null; for(int i = depth; i-- > 0; ) { Node node = path[i]; Node left = node.Left; if ((left != null) && (left != child)) { succeeds = true; break; } child = node; } } return succeeds; } } /// /// Indicates whether there is a successor node for a current node. /// public bool HasSuccessor { get { bool succeeds = false; if (depth != 0) { var path = this.path; Node child = null; for(int i = depth; i-- > 0; ) { Node node = path[i]; Node right = node.Right; if ((right != null) && (right != child)) { succeeds = true; break; } child = node; } } return succeeds; } } #region ICollection Members /// /// Gets a value indicating whether the collection is readonly. /// public bool IsReadOnly { get { return false; } } /// /// Adds an item to the collection after the current position. /// /// A value to add public void Add(V value) { Insert(value, false); } /// /// Removes all items from the collection. /// public void Clear() { MoveToNull(); } /// /// Determines whether the collection contains a specific value. /// /// A value to locate. /// /// true if value is found, and false otherwise. /// If value is found then navigator is positioned to a node with that value. /// public bool Contains(V value) { bool succeeds = false; if (!IsNull) { var comparer = EqualityComparer.Default; MoveToRoot(); MoveToLeftmost(); do { if (comparer.Equals(Current.Value, value)) { succeeds = true; break; } } while(MoveToSuccessor()); } return succeeds; } /// /// Copies the elements of the collection to an array, starting at a /// particular array index. /// /// /// An array that is the destination of the elements copied /// from the collection. /// /// /// An index in array at which copying begins. /// public void CopyTo(V[] array, int index) { if (array == null) { throw new ArgumentException("array"); } if (index < 0) { throw new ArgumentException("index"); } if ((array.Length - index) < Count) { throw new ArgumentException("array"); } if (!IsNull) { var navigator = Root.Navigator(); navigator.MoveToLeftmost(); do { array[index++] = navigator.Current.Value; } while(navigator.MoveToSuccessor()); } } /// /// Removes the first occurrence of a specific value from the collection. /// /// A value to remove. /// /// true if item was successfully removed from the collection, and false otherwise. /// This method also returns false if value is not found in the original collection. /// public bool Remove(V value) { bool succeed = false; if (Contains(value)) { Remove(); succeed = true; } return succeed; } /// /// Gets node enumerator. /// /// A node enumerator. public IEnumerator GetEnumerator() { if (!IsNull) { var navigator = Root.Navigator(); navigator.MoveToLeftmost(); do { yield return navigator.Current.Value; } while(navigator.MoveToSuccessor()); } } /// /// Gets a node enumerator. /// /// A node enumerator. System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion #region IList Members /// /// Gets count of nodes in the tree. /// public int Count { get { return depth == 0 ? 0 : path[0].Size; } } /// /// Gets or sets the element at the specified index. /// /// /// A zero-based index of the element to get or set. /// /// An element at the specified index. public V this[int index] { get { if (!MoveToIndex(index)) { throw new ArgumentOutOfRangeException("index"); } return Current.Value; } set { if (!MoveToIndex(index)) { throw new ArgumentOutOfRangeException("index"); } Replace(value); } } /// /// Determines the index of a specific item in the list. /// /// An item to locate. /// /// An index of item if found in the list, or -1 otherwise. /// public int IndexOf(V value) { return !Contains(value) ? -1 : Index; } /// /// Inserts an item to the list at the specified index. /// Note that index is not accounted but key only. /// /// /// A zero-based index at which item should be inserted. /// /// An item to insert. public void Insert(int index, V item) { if (index == Count) { if (index > 0) { MoveToIndex(index - 1); } Insert(item, false); } else { if (!MoveToIndex(index - 1)) { throw new ArgumentOutOfRangeException("index"); } Insert(item, true); } } /// /// Removes a list item at the specified index. /// /// /// An index of item to remove. /// public void RemoveAt(int index) { if (!MoveToIndex(index)) { throw new IndexOutOfRangeException("index"); } Remove(); } #endregion /// /// Gets a node in the path. /// /// A node depth. /// A node in the node path. public Node GetPath(int index) { return (index >= 0) && (index <= depth) ? path[index] : null; } /// /// Moves to the null node. /// /// always returns true. public bool MoveToNull() { var path = this.path; for(int i = 0; i < path.Length; ++i) { if (i >= depth) { break; } path[i] = null; } depth = 0; current = null; return false; } /// /// Moves to a tree root, if any. /// /// /// true if after navigation succeeds, and false otherwise. /// If navigation succeeds then Current is changed to a new node, otherwise /// Current is not changed. /// public bool MoveToRoot() { bool succeeds = false; int depth = this.depth; if (depth == 1) { succeeds = true; } else if (depth > 1) { var path = this.path; for(int i = 1; i < path.Length; ++i) { if (i >= depth) { break; } path[i] = null; } current = path[0]; this.depth = 1; succeeds = true; } return succeeds; } /// /// Moves to a parent node, if any. /// /// /// true if after navigation succeeds, and false otherwise. /// If navigation succeeds then Current is changed to a new node, otherwise /// Current is not changed. /// public bool MoveToParent() { bool succeeds = false; if (depth > 1) { var path = this.path; path[--depth] = null; current = path[depth - 1]; succeeds = true; } return succeeds; } /// /// Moves to a left child node, if any. /// /// /// true if after navigation succeeds, and false otherwise. /// If navigation succeeds then Current is changed to a new node, otherwise /// Current is not changed. /// public bool MoveToLeft() { bool succeeds = false; Node node = current; if (node != null) { node = node.Left; if (node != null) { var path = this.path; if (path.Length <= depth) { path = ReserveDepth(depth + 1); } path[depth++] = node; current = node; succeeds = true; } } return succeeds; } /// /// Moves to a right child node, if any. /// /// /// true if after navigation succeeds, and false otherwise. /// If navigation succeeds then Current is changed to a new node, otherwise /// Current is not changed. /// public bool MoveToRight() { bool succeeds = false; Node node = current; if (node != null) { node = node.Right; if (node != null) { var path = this.path; if (path.Length <= depth) { path = ReserveDepth(depth + 1); } path[depth++] = node; current = node; succeeds = true; } } return succeeds; } /// /// Moves to the leftmost node of the subtree rooted by the current node, /// if any. /// /// /// true if after navigation succeeds, and false otherwise. /// If navigation succeeds then Current is changed to a new node, otherwise /// Current is not changed. /// public bool MoveToLeftmost() { bool succeeds = false; Node node = current; if (node != null) { Node left = node.Left; if (left != null) { var path = this.path; do { node = left; left = node.Left; if (path.Length <= depth) { path = ReserveDepth(depth + 1); } path[depth++] = node; } while(left != null); current = node; } succeeds = true; } return succeeds; } /// /// Moves to the rightmost node of the subtree rooted by the current node, /// if any. /// /// /// true if after navigation succeeds, and false otherwise. /// If navigation succeeds then Current is changed to a new node, otherwise /// Current is not changed. /// public bool MoveToRightmost() { bool succeeds = false; Node node = current; if (node != null) { Node right = node.Right; if (right != null) { var path = this.path; do { node = right; right = node.Right; if (path.Length <= depth) { path = ReserveDepth(depth + 1); } path[depth++] = node; } while(right != null); current = node; } succeeds = true; } return succeeds; } /// /// Moves to the predecessor node, if any. /// /// /// true if after navigation succeeds, and false otherwise. /// If navigation succeeds then Current is changed to a new node, otherwise /// Current is not changed. /// public bool MoveToPredecessor() { bool succeeds = false; Node node = current; if (node != null) { Node next = node.Left; var path = this.path; if (next != null) { if (path.Length <= depth) { path = ReserveDepth(depth + 1); } path[depth++] = next; node = next; next = node.Right; while(next != null) { if (path.Length <= depth) { path = ReserveDepth(depth + 1); } path[depth++] = next; node = next; next = next.Right; } } else { int i = depth; do { if (--i == 0) { goto End; } next = node; node = path[i - 1]; } while(next == node.Left); while(depth > i) { path[--depth] = null; } } current = node; succeeds = true; } End: return succeeds; } /// /// Moves to the successor node, if any. /// /// /// true if after navigation succeeds, and false otherwise. /// If navigation succeeds then Current is changed to a new node, otherwise /// Current is not changed. /// public bool MoveToSuccessor() { bool succeeds = false; Node node = current; if (node != null) { Node next = node.Right; var path = this.path; if (next != null) { if (path.Length <= depth) { path = ReserveDepth(depth + 1); } path[depth++] = next; node = next; next = node.Left; while(next != null) { if (path.Length <= depth) { path = ReserveDepth(depth + 1); } path[depth++] = next; node = next; next = next.Left; } } else { int i = depth; do { if (--i == 0) { goto End; } next = node; node = path[i - 1]; } while(next == node.Right); while(depth > i) { path[--depth] = null; } } current = node; succeeds = true; } End: return succeeds; } /// /// Moves to a node with a specified index. /// /// A node index. /// /// true if after navigation succeeds, and false otherwise. /// If navigation succeeds then Current is changed to a new node, otherwise /// Current is not changed. /// public bool MoveToIndex(int index) { bool succeeds = false; if ((index >= 0) && (index < Count)) { MoveToRoot(); var path = this.path; Node node = current; Node next = node.Left; int i = next != null ? next.Size : 0; while(index != i) { if (index > i) { node = node.Right; next = node.Left; i += next != null ? next.Size + 1 : 1; } else { node = node.Left; next = node.Right; i -= next != null ? next.Size + 1 : 1; } if (path.Length <= depth) { path = ReserveDepth(depth + 1); } path[depth++] = node; } current = node; succeeds = true; } return succeeds; } /// /// Insert a new node before or after a specified node. /// After insertion navigator points to the root of the tree. /// Use Index property and MoveToIndex() method to navigate to the /// inserted property. /// /// A value to insert. /// /// true to insert before, and false to insert after. /// /// /// If node has children then tree may be disbalanced. /// public void Insert(V value, bool before) { var path = this.path; Node node; if (depth == 0) { if (path.Length < 1) { path = ReserveDepth(1); } node = new Node(value); path[0] = node; current = node; depth = 1; return; } Node parent = current; if (before) { if (parent.Left != null) { MoveToPredecessor(); parent = current; before = false; } } else { if (parent.Right != null) { MoveToSuccessor(); parent = current; before = true; } } Node left; Node right; if (parent.Size == 1) { // This branch is pure allocation optimization. if (depth == 1) { node = before ? new Node(null, parent, value) : new Node(parent, null, value); path[0] = node; current = node; return; } path[--depth] = null; Node grand = path[depth - 1]; if (grand.Size == 2) { node = new Node(null, null, grand); node = grand.Left == parent ? before ? new Node(new Node(value), node, parent) : new Node(parent, node, value) : before ? new Node(node, parent, value) : new Node(node, new Node(value), parent); if (depth == 1) { path[0] = node; current = node; return; } parent = grand; path[--depth] = null; grand = path[depth - 1]; } else { node = before ? new Node(null, parent, value) : new Node(parent, null, value); } current = grand; left = grand.Left; if (left == parent) { left = node; right = grand.Right; } else { right = node; } } else { node = new Node(value); if (before) { left = node; right = parent.Right; } else { left = parent.Left; right = node; } } Balance(left, right); } /// /// Replaces the current value. /// /// A new value. /// /// true if after navigation succeeds, and false otherwise. /// If navigation succeeds then Current is changed to a new node, otherwise /// Current is not changed. /// public bool Replace(V value) { bool succeeds = false; Node node = current; if (node != null) { Replace(new Node(node.Left, node.Right, value)); succeeds = true; } return succeeds; } /// /// Removes current node from the tree. /// After remove navigator points to the root of the tree. /// Use Index property and MoveToIndex() method to navigate to the /// inserted property. /// /// /// true if after operation, Current is not null, and false otherwise. /// public bool Remove() { bool succeeds = false; Node node = current; if (node != null) { Node left = node.Left; Node right = node.Right; if ((left != null) && (right != null)) { RemoveAndBalance(); succeeds = true; } else if (depth == 1) { // Delete root node. if (left == null) { if (right == null) { // Remove last node. MoveToNull(); } else { path[0] = right; current = right; succeeds = true; } } else { path[0] = left; current = left; succeeds = true; } } else { Node parent = path[depth - 2]; if (left == null) { if (right == null) { // Remove leaf node. left = parent.Left; if (left == node) { left = null; right = parent.Right; } else { right = null; } } else { // There is only a right child. left = parent.Left; if (left == node) { left = right; right = parent.Right; } } } else { // There is only a left child. right = parent.Right; if (right == node) { right = left; left = parent.Left; } } Balance(left, right); succeeds = true; } } return succeeds; } /// /// Creates a well balanced tree from a collection of values. /// /// Values collection. /// Well balanced tree, or null if values is null. public static Node Create(ICollection values) { Node result = null; if (values != null) { using (IEnumerator enumerator = values.GetEnumerator()) { result = Create(enumerator, values.Count); } } return result; } /// /// Creates a well balanced tree from a collection of values. /// /// Values collection. /// Well balanced tree, or null if values is null. public static Node Create(IEnumerator values, int count) { Node result = null; if ((values != null) && (count > 0)) { int leftCount = count / 2; int rightCount = count - leftCount - 1; Node left = leftCount > 0 ? Create(values, leftCount) : null; values.MoveNext(); V value = values.Current; Node right = rightCount > 0 ? Create(values, rightCount) : null; result = new Node(left, right, value); } return result; } /// /// Gets subtree height for the balanced subtree size. /// /// Subtree size /// Subtree height public static int Height(int size) { int result = 0; if (size != 0) { if ((size & 0xffff0000) == 0) { result -= 16; size <<= 16; } if ((size & 0xff000000) == 0) { result -= 8; size <<= 8; } if ((size & 0xf0000000) == 0) { result -= 4; size <<= 4; } if ((size & 0xc0000000) == 0) { result -= 2; size <<= 2; } result += (int)((uint)size >> 31) + 31; } return result; } /// /// Reserves path for the depth. /// /// A required length. /// /// A new path. /// private Node[] ReserveDepth(int length) { if (length < 8) { length = 8; } else if (length < 16) { length = 16; } else if (length < 24) { length = 24; } else if (length < 32) { length = 32; } // No more cases. var newPath = new Node[length]; var path = this.path; for(int i = 0; i < path.Length; ++i) { if (i >= depth) { break; } newPath[i] = path[i]; } this.path = newPath; return newPath; } /// /// Replaces the current node. /// /// A new node. private void Replace(Node newNode) { Node node = current; var path = this.path; path[depth - 1] = newNode; current = newNode; for(int i = depth - 1; i-- > 0;) { Node parent = path[i]; Node left = parent.Left; Node right; if (left == node) { left = newNode; right = parent.Right; } else { right = newNode; } node = parent; newNode = new Node(left, right, parent); path[i] = newNode; } } /// /// Removes node with two children and balances the tree. /// private void RemoveAndBalance() { int i = depth - 1; Node node = current; Node parent; Node newParent; Node left; Node right; Node newNode; if (node.Left.Size >= node.Right.Size) { MoveToPredecessor(); MoveToParent(); parent = current; if (i == depth - 1) { newParent = parent.Left; left = parent.Left.Left; right = parent.Right; } else { node = parent; newParent = parent.Right; left = parent.Left; right = parent.Right.Left; } } else { MoveToSuccessor(); MoveToParent(); parent = current; if (i == depth - 1) { newParent = parent.Right; left = parent.Left; right = parent.Right.Right; } else { node = parent; newParent = parent.Left; left = parent.Left.Right; right = parent.Right; } } int j = depth - 1; var path = this.path; while(j > i) { newNode = new Node(left, right, node); path[j] = null; parent = path[--j]; left = parent.Left; if (left == node) { left = newNode; right = parent.Right; } else { right = newNode; } node = parent; } depth = i + 1; newNode = new Node(left, right, newParent); Replace(newNode); Balance(newNode.Left, newNode.Right); } /// Balances the tree. /// A left child. /// A right child. private void Balance(Node left, Node right) { Node node = current; int i = depth; var path = this.path; while(true) { path[--i] = null; Node newNode; Node leftLeft; Node leftRight; Node rightRight; Node rightLeft; int l; int r; int ll; int lr; int rr; int rl; if (left != null) { l = left.Size; leftLeft = left.Left; leftRight = left.Right; ll = leftLeft != null ? leftLeft.Size : 0; lr = leftRight != null ? leftRight.Size : 0; } else { leftLeft = null; leftRight = null; l = 0; ll = 0; lr = 0; } if (right != null) { rightRight = right.Right; rightLeft = right.Left; r = right.Size; rr = rightRight != null ? rightRight.Size : 0; rl = rightLeft != null ? rightLeft.Size : 0; } else { rightRight = null; rightLeft = null; r = 0; rr = 0; rl = 0; } if ((ll > r) && (ll > lr)) { // LL newNode = new Node( leftLeft, new Node(leftRight, right, node), left); } else if ((lr > r) || ((ll == r) && (leftRight != null) && (leftRight.Left != null))) { // LR newNode = new Node( new Node(leftLeft, leftRight.Left, left), new Node(leftRight.Right, right, node), leftRight); } else if ((rr > l) && (rr > rl)) { // RR newNode = new Node( new Node(left, rightLeft, node), rightRight, right); } else if ((rl > l) || ((rr == l) && (rightLeft != null) && (rightLeft.Right != null))) { // RL newNode = new Node( new Node(left, rightLeft.Left, node), new Node(rightLeft.Right, rightRight, right), rightLeft); } else { newNode = (node.Left == left) && (node.Right == right) ? node : new Node(left, right, node); } if (i == 0) { current = newNode; path[0] = newNode; depth = 1; break; } Node next = path[i - 1]; left = next.Left; if (left == node) { left = newNode; right = next.Right; } else { right = newNode; } node = next; } } /// /// A current node. /// private Node current; /// /// A node path. /// private Node[] path = empty; /// /// A depth of path. /// private int depth; /// /// Empty path. /// private static readonly Node[] empty = {}; } /// /// An API to work with tree. /// public static class API { /// /// Gets a tree navigator for a node. /// /// A node to get a tree navigator for. /// A tree navigator. public static TreeNavigator Navigator( this TreeNavigator.Node node) { return new TreeNavigator(node); } /// /// Navigates to a node within a tree, which is equal or closest to /// a specified key. /// /// A tree navigator. /// A key of a find. /// /// 0 when current node is equal to, /// -1 when found node is less than, and /// 1 when found node is greater than the searched one. /// /// If tree is empty then 1 is returned. /// /// A key type. /// /// Method works properly wheNode nodes in the tree are ordered /// according to the key. /// public static int Find(this TreeNavigator navigator, K key) { return Find(navigator, key, Comparer.Default); } /// /// Navigates to a node within a tree, which is equal or closest to /// a specified key. Comparer is used to test equality. /// /// A tree navigator. /// A key of a find. /// A key comparer. /// /// 0 when current node is equal to, /// -1 when found node is less than, and /// 1 when found node is greater than the searched one. /// /// If tree is empty then 1 is returned. /// /// A key type. /// /// Method works properly wheNode nodes in the tree are ordered /// according to the comparer. /// public static int Find( this TreeNavigator navigator, K key, IComparer comparer) { int c; if (!navigator.MoveToRoot()) { c = -1; } else { while(true) { c = comparer.Compare(navigator.Current.Value, key); if ((c == 0) || (c < 0 ? !navigator.MoveToRight() : !navigator.MoveToLeft())) { break; } } } return c; } /// /// Navigates to a node within a tree, which is equal or closest to /// a specified value. /// /// A tree navigator. /// A key value of a find. /// /// 0 when current node is equal to, /// -1 when found node is less than, and /// 1 when found node is greater than the searched one. /// /// If tree is empty then 1 is returned. /// /// A key type. /// A value type. /// /// Method works properly wheNode nodes in the tree are ordered /// according to the key. /// public static int Find( this TreeNavigator> navigator, K key) { return Find(navigator, key, Comparer.Default); } /// /// Navigates to a node within a tree, which is equal or closest to /// a specified value. Comparer is used to test equality. /// /// A tree navigator. /// A key value of a find. /// A key comparer. /// /// 0 when current node is equal to, /// -1 when found node is less than, and /// 1 when found node is greater than the searched one. /// /// If tree is empty then 1 is returned. /// /// A key type. /// A value type. /// /// Method works properly wheNode nodes in the tree are ordered /// according to the comparer. /// public static int Find( this TreeNavigator> navigator, K key, IComparer comparer) { int c; if (!navigator.MoveToRoot()) { c = -1; } else { while(true) { c = comparer.Compare(navigator.Current.Value.Key, key); if ((c == 0) || (c < 0 ? !navigator.MoveToRight() : !navigator.MoveToLeft())) { break; } } } return c; } /// /// Navigates to a node within a tree, which is equal to a specified value. /// Comparer is used to test equality. /// /// A node. /// A key of a find. /// Found node or null if node is not found. /// A key type. /// /// Method works properly wheNode nodes in the tree are ordered /// according to the key. /// public static TreeNavigator.Node Find( this TreeNavigator.Node node, K key) { return Find(node, key, Comparer.Default); } /// /// Navigates to a node within a tree, which is equal to a specified value. /// Comparer is used to test equality. /// /// A node. /// A key of a find. /// A key comparer. /// Found node or null if node is not found. /// A key type. /// /// Method works properly wheNode nodes in the tree are ordered /// according to the comparer. /// public static TreeNavigator.Node Find( this TreeNavigator.Node node, K key, IComparer comparer) { while(node != null) { int c = comparer.Compare(node.Value, key); if (c == 0) { break; } node = c < 0 ? node.Right : node.Left; } return node; } /// /// Navigates to a node within a tree, which is equal to a specified value. /// Comparer is used to test equality. /// /// A node. /// A key value of a find. /// Found node or null if node is not found. /// A key type. /// A value type. /// /// Method works properly wheNode nodes in the tree are ordered /// according to the key. /// public static TreeNavigator>.Node Find( this TreeNavigator>.Node node, K key) { return Find(node, key, Comparer.Default); } /// /// Navigates to a node within a tree, which is equal to a specified value. /// Comparer is used to test equality. /// /// A node. /// A key value of a find. /// A key comparer. /// Found node or null if node is not found. /// A key type. /// A value type. /// /// Method works properly wheNode nodes in the tree are ordered /// according to the comparer. /// public static TreeNavigator>.Node Find( this TreeNavigator>.Node node, K key, IComparer comparer) { while(node != null) { int c = comparer.Compare(node.Value.Key, key); if (c == 0) { break; } node = c < 0 ? node.Right : node.Left; } return node; } /// /// Inserts a node with a specified key into the tree. /// /// A tree navigator. /// A key to insert. /// A key comparer. /// /// Index of inserted node, or negative index of node /// if no node is not inserted due to duplicate. /// /// A key type. public static int Insert( this TreeNavigator navigator, K key, IComparer comparer) { return Insert(navigator, key, comparer, false); } /// /// Inserts a node with a specified key into the tree. /// /// A tree navigator. /// A key to insert. /// A key comparer. /// /// Index of inserted node, or negative index of node /// if no node is not inserted due to duplicate. /// /// A key type. public static int Insert(this TreeNavigator navigator, K key) { return Insert(navigator, key, Comparer.Default, false); } /// /// Inserts a node with a specified key into the tree. /// /// A tree navigator. /// A key to insert. /// /// true to insert duplicate, and false otherwise. /// /// /// Index of inserted node, or negative index of node /// if no node is not inserted due to duplicate. /// /// A key type. public static int Insert( this TreeNavigator navigator, K key, bool insertDuplicate) { return Insert(navigator, key, Comparer.Default, insertDuplicate); } /// /// Inserts a node with a specified key into the tree. /// /// A tree navigator. /// A key to insert. /// A key comparer. /// /// true to insert duplicate, and false otherwise. /// /// /// Index of inserted node, or negative index of node /// if no node is not inserted due to duplicate. /// /// A key type. public static int Insert( this TreeNavigator navigator, K key, IComparer comparer, bool insertDuplicate) { int c = Find(navigator, key, comparer); int index = navigator.Index; if ((c == 0) && !insertDuplicate) { index = -index; } else { if (c <= 0) { ++index; } navigator.Insert(key, c > 0); } return index; } /// /// Inserts a node with a specified key into the tree. /// /// A tree navigator. /// A value to insert. /// A key comparer. /// /// Index of inserted node, or negative index of node /// if no node is not inserted due to duplicate. /// /// A key type. /// A value type. public static int Insert( this TreeNavigator> navigator, KeyValuePair value, IComparer comparer) { return Insert(navigator, value, comparer, false); } /// /// Inserts a node with a specified key into the tree. /// /// A tree navigator. /// A value to insert. /// /// Index of inserted node, or negative index of node /// if no node is not inserted due to duplicate. /// /// A key type. /// A value type. public static int Insert( this TreeNavigator> navigator, KeyValuePair value) { return Insert(navigator, value, Comparer.Default, false); } /// /// Inserts a node with a specified key into the tree. /// /// A tree navigator. /// A value to insert. /// /// true to insert duplicate, and false otherwise. /// /// /// Index of inserted node, or negative index of node /// if no node is not inserted due to duplicate. /// /// A key type. /// A value type. public static int Insert( this TreeNavigator> navigator, KeyValuePair value, bool insertDuplicate) { return Insert(navigator, value, Comparer.Default, insertDuplicate); } /// /// Inserts a node with a specified key into the tree. /// /// A tree navigator. /// A value to insert. /// A key comparer. /// /// true to insert duplicate, and false otherwise. /// /// /// Index of inserted node, or negative index of node /// if no node is not inserted due to duplicate. /// /// A key type. /// A value type. public static int Insert( this TreeNavigator> navigator, KeyValuePair value, IComparer comparer, bool insertDuplicate) { int c = Find(navigator, value.Key, comparer); int index = navigator.Index; if ((c == 0) && !insertDuplicate) { index = -index; } else { if (c <= 0) { ++index; } navigator.Insert(value, c > 0); } return index; } /// /// Removes a node with a specified key. /// /// A tree navigator. /// A key to remove. /// /// Index of removed nore, or -1 if no node is removed. /// /// A key type. public static int Remove(this TreeNavigator navigator, K key) { return Remove(navigator, key, Comparer.Default); } /// /// Removes a node with a specified key. /// /// A tree navigator. /// A key to remove. /// A key comparer. /// /// Index of removed nore, or -1 if no node is removed. /// /// A key type. public static int Remove( this TreeNavigator navigator, K key, IComparer comparer) { int index; int c = Find(navigator, key, comparer); if (c != 0) { index = -1; } else { index = navigator.Index; navigator.Remove(); } return index; } /// /// Removes a node with a specified key. /// /// A tree navigator. /// A key to remove. /// /// Index of removed nore, or -1 if no node is removed. /// /// A key type. /// A value type. public static int Remove( this TreeNavigator> navigator, K key) { return Remove(navigator, key, Comparer.Default); } /// /// Removes a node with a specified key. /// /// A tree navigator. /// A key to remove. /// A key comparer. /// /// Index of removed nore, or -1 if no node is removed. /// /// A key type. public static int Remove( this TreeNavigator> navigator, K key, IComparer comparer) { int index; int c = Find(navigator, key, comparer); if (c != 0) { index = -1; } else { index = navigator.Index; navigator.Remove(); } return index; } /// /// Enumerates values for a specified key. /// /// A tree navigator. /// A key to get values for. /// An enumerator. /// A key type. /// A value type. public static IEnumerable> GetValues( this TreeNavigator> navigator, K key) { return GetValues(navigator, key, Comparer.Default); } /// /// Enumerates values for a specified key. /// /// A tree navigator. /// A key to get values for. /// A key comparer. /// An enumerator. /// A key type. /// A value type. public static IEnumerable> GetValues( this TreeNavigator> navigator, K key, IComparer comparer) { navigator = navigator.Root.Navigator(); int c = Find(navigator, key, comparer); if (c == 0) { while(navigator.MoveToPredecessor()) { if (comparer.Compare(navigator.Current.Value.Key, key) != 0) { navigator.MoveToSuccessor(); break; } } do { yield return navigator.Current.Value; } while(navigator.MoveToSuccessor() && (comparer.Compare(navigator.Current.Value.Key, key) != 0)); } } } }