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 = default!; public AVLNode Right = default!; public AVLNode(TKey value) { this.Value = value; } } AVLNode root = default!; 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 this.count; } } /// /// True if the collection is readonly. False otherwise. /// public bool IsReadOnly => this.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) { this.count++; var newItem = new AVLNode(value); if (this.root == null) { this.root = newItem; } else { this.root = this.RecursiveInsertion(this.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) { var node = this.Find(value, this.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) { this.root = this.Delete(this.root, value)!; return true; } /// /// Clears the tree. /// public void Clear() { var queue = new Queue>(); queue.Enqueue(this.root); while (queue.Count > 0) { var currentNode = queue.Dequeue(); if (currentNode.Left != null) { queue.Enqueue(currentNode.Left); currentNode.Left = default!; this.count--; } if (currentNode.Right != null) { queue.Enqueue(currentNode.Right); currentNode.Right = default!; this.count--; } } this.root = default!; this.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) { var queue = new Queue>(); queue.Enqueue(this.root); while (queue.Count > 0) { var 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 this.GetEnumerator(this.root); } /// /// Copies the tree structure into an array. /// /// Array containing the values contained in the tree. public T[] ToArray() { var array = new T[this.count]; this.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 = this.RecursiveInsertion(current.Left, n); current = this.BalanceTree(current); } else if (n.Value.CompareTo(current.Value) > 0) { current.Right = this.RecursiveInsertion(current.Right, n); current = this.BalanceTree(current); } return current; } private AVLNode BalanceTree(AVLNode current) { var b_factor = this.BalanceFactor(current); if (b_factor > 1) { if (this.BalanceFactor(current.Left) > 0) { current = this.RotateLL(current); } else { current = this.RotateLR(current); } } else if (b_factor < -1) { if (this.BalanceFactor(current.Right) > 0) { current = this.RotateRL(current); } else { current = this.RotateRR(current); } } return current; } private AVLNode? Delete(AVLNode current, T target) { if (current == null) { return null; } else { //left subtree if (target.CompareTo(current.Value) < 0) { current.Left = this.Delete(current.Left, target)!; if (this.BalanceFactor(current) == -2)//here { if (this.BalanceFactor(current.Right) <= 0) { current = this.RotateRR(current); } else { current = this.RotateRL(current); } } } //right subtree else if (target.CompareTo(current.Value) > 0) { current.Right = this.Delete(current.Right, target)!; if (this.BalanceFactor(current) == 2) { if (this.BalanceFactor(current.Left) >= 0) { current = this.RotateLL(current); } else { current = this.RotateLR(current); } } } //if target is found else { this.count--; if (current.Right != null) { //delete its inorder successor var parent = current.Right; while (parent.Left != null) { parent = parent.Left; } current.Value = parent.Value; current.Right = this.Delete(current.Right, parent.Value)!; if (this.BalanceFactor(current) == 2)//rebalancing { if (this.BalanceFactor(current.Left) >= 0) { current = this.RotateLL(current); } else { current = this.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 this.Find(target, current.Left); } } else { if (target.CompareTo(current.Value) == 0) { return current; } else { return this.Find(target, current.Right); } } } private int Max(int l, int r) { return l > r ? l : r; } private int GetHeight(AVLNode current) { var height = 0; if (current != null) { var l = this.GetHeight(current.Left); var r = this.GetHeight(current.Right); var m = this.Max(l, r); height = m + 1; } return height; } private int BalanceFactor(AVLNode current) { var l = this.GetHeight(current.Left); var r = this.GetHeight(current.Right); var b_factor = l - r; return b_factor; } private AVLNode RotateRR(AVLNode parent) { var pivot = parent.Right; parent.Right = pivot.Left; pivot.Left = parent; return pivot; } private AVLNode RotateLL(AVLNode parent) { var pivot = parent.Left; parent.Left = pivot.Right; pivot.Right = parent; return pivot; } private AVLNode RotateLR(AVLNode parent) { var pivot = parent.Left; parent.Left = this.RotateRR(pivot); return this.RotateLL(parent); } private AVLNode RotateRL(AVLNode parent) { var pivot = parent.Right; parent.Right = this.RotateLL(pivot); return this.RotateRR(parent); } IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } private IEnumerator GetEnumerator(AVLNode rootNode) { var queue = new Queue>(); queue.Enqueue(rootNode); while (queue.Count > 0) { var currentNode = queue.Dequeue(); yield return currentNode.Value; if (currentNode.Left != null) { queue.Enqueue(currentNode.Left); } if (currentNode.Right != null) { queue.Enqueue(currentNode.Right); } } } #endregion }