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
}
}