using System.Collections.Generic; namespace System.Collections.Generic { /// /// AVL tree implementation. /// Thanks to Karim Oumghar for the implementation example. /// Read on https://simpledevcode.wordpress.com/2014/09/16/avl-tree-in-c/ /// /// Provided type. [Serializable] public sealed class AVLTree : ICollection where T : IComparable { #region Fields [Serializable] private class AVLNode { public TKey Value; public AVLNode Left; public AVLNode Right; public AVLNode(TKey value) { this.Value = value; } } AVLNode root; private int count = 0; private readonly bool isReadOnly = false; #endregion #region Properties /// /// Count of items currently stored in the tree. /// public int Count { get { return count; } } /// /// True if the collection is readonly. False otherwise. /// public bool IsReadOnly => isReadOnly; #endregion #region Constructors /// /// Initializes a new instance of an AVLTree collection. /// public AVLTree() { } #endregion #region Public Methods /// /// Adds the value to the tree. /// /// Value to be added to the tree. public void Add(T value) { count++; AVLNode newItem = new AVLNode(value); if (root == null) { root = newItem; } else { root = RecursiveInsertion(root, newItem); } } /// /// Checks if the key is contained into the tree. /// /// Value to be checked if present in the tree. /// True if the value is in the tree. public bool Contains(T value) { AVLNode node = Find(value, root); if (node == null) { return false; } if (node.Value.CompareTo(value) == 0) { return true; } else { return false; } } /// /// Removes the specified value from the tree. /// /// Value to be deleted. public bool Remove(T value) { root = Delete(root, value); return true; } /// /// Clears the tree. /// public void Clear() { Queue> queue = new Queue>(); queue.Enqueue(root); while (queue.Count > 0) { AVLNode currentNode = queue.Dequeue(); if (currentNode.Left != null) { queue.Enqueue(currentNode.Left); currentNode.Left = null; count--; } if (currentNode.Right != null) { queue.Enqueue(currentNode.Right); currentNode.Right = null; count--; } } root = null; count--; } /// /// Copies the tree onto the provided array. /// /// Array to store the values in the tree. /// Starting index of the provided array. public void CopyTo(T[] array, int arrayIndex) { Queue> queue = new Queue>(); queue.Enqueue(root); while (queue.Count > 0) { AVLNode currentNode = queue.Dequeue(); array[arrayIndex++] = currentNode.Value; if (currentNode.Left != null) { queue.Enqueue(currentNode.Left); } if (currentNode.Right != null) { queue.Enqueue(currentNode.Right); } } } /// /// Enumerator that iterates over the tree. /// /// public IEnumerator GetEnumerator() { return GetEnumerator(root); } /// /// Copies the tree structure into an array. /// /// Array containing the values contained in the tree. public T[] ToArray() { T[] array = new T[count]; CopyTo(array, 0); return array; } #endregion #region Private Methods private AVLNode RecursiveInsertion(AVLNode current, AVLNode n) { if (current == null) { current = n; return current; } else if (n.Value.CompareTo(current.Value) < 0) { current.Left = RecursiveInsertion(current.Left, n); current = BalanceTree(current); } else if (n.Value.CompareTo(current.Value) > 0) { current.Right = RecursiveInsertion(current.Right, n); current = BalanceTree(current); } return current; } private AVLNode BalanceTree(AVLNode current) { int b_factor = BalanceFactor(current); if (b_factor > 1) { if (BalanceFactor(current.Left) > 0) { current = RotateLL(current); } else { current = RotateLR(current); } } else if (b_factor < -1) { if (BalanceFactor(current.Right) > 0) { current = RotateRL(current); } else { current = RotateRR(current); } } return current; } private AVLNode Delete(AVLNode current, T target) { AVLNode parent; if (current == null) { return null; } else { //left subtree if (target.CompareTo(current.Value) < 0) { current.Left = Delete(current.Left, target); if (BalanceFactor(current) == -2)//here { if (BalanceFactor(current.Right) <= 0) { current = RotateRR(current); } else { current = RotateRL(current); } } } //right subtree else if (target.CompareTo(current.Value) > 0) { current.Right = Delete(current.Right, target); if (BalanceFactor(current) == 2) { if (BalanceFactor(current.Left) >= 0) { current = RotateLL(current); } else { current = RotateLR(current); } } } //if target is found else { count--; if (current.Right != null) { //delete its inorder successor parent = current.Right; while (parent.Left != null) { parent = parent.Left; } current.Value = parent.Value; current.Right = Delete(current.Right, parent.Value); if (BalanceFactor(current) == 2)//rebalancing { if (BalanceFactor(current.Left) >= 0) { current = RotateLL(current); } else { current = RotateLR(current); } } } else { //if current.left != null return current.Left; } } } return current; } private AVLNode Find(T target, AVLNode current) { if (current == null) { return null; } if (target.CompareTo(current.Value) < 0) { if (target.CompareTo(current.Value) == 0) { return current; } else return Find(target, current.Left); } else { if (target.CompareTo(current.Value) == 0) { return current; } else return Find(target, current.Right); } } private int Max(int l, int r) { return l > r ? l : r; } private int GetHeight(AVLNode current) { int height = 0; if (current != null) { int l = GetHeight(current.Left); int r = GetHeight(current.Right); int m = Max(l, r); height = m + 1; } return height; } private int BalanceFactor(AVLNode current) { int l = GetHeight(current.Left); int r = GetHeight(current.Right); int b_factor = l - r; return b_factor; } private AVLNode RotateRR(AVLNode parent) { AVLNode pivot = parent.Right; parent.Right = pivot.Left; pivot.Left = parent; return pivot; } private AVLNode RotateLL(AVLNode parent) { AVLNode pivot = parent.Left; parent.Left = pivot.Right; pivot.Right = parent; return pivot; } private AVLNode RotateLR(AVLNode parent) { AVLNode pivot = parent.Left; parent.Left = RotateRR(pivot); return RotateLL(parent); } private AVLNode RotateRL(AVLNode parent) { AVLNode pivot = parent.Right; parent.Right = RotateLL(pivot); return RotateRR(parent); } IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } private IEnumerator GetEnumerator(AVLNode rootNode) { Queue> queue = new Queue>(); queue.Enqueue(rootNode); while (queue.Count > 0) { AVLNode currentNode = queue.Dequeue(); yield return currentNode.Value; if (currentNode.Left != null) { queue.Enqueue(currentNode.Left); } if (currentNode.Right != null) { queue.Enqueue(currentNode.Right); } } } #endregion } }