/// <summary> /// Recursive add or update used in indexer. /// </summary> private AVLTreeMapNode <TKey, TValue> AddOrUpdate(AVLTreeMapNode <TKey, TValue> node, TKey key, TValue value, out bool updated) { updated = false; if (node == null) { return(new AVLTreeMapNode <TKey, TValue>(key, value)); } int cmp = comparer.Compare(key, node.Key); if (cmp < 0) { node.Left = AddOrUpdate(node.Left, key, value, out updated); } else if (cmp > 0) { node.Right = AddOrUpdate(node.Right, key, value, out updated); } else { node.Value = value; updated = true; // mark that value is updated return(node); } if (updated) // if only updated, no need to balance { return(node); } else { return(Balance(node)); } }
/// <summary> /// Fixes the node height, calculating it from its children. /// </summary> private void FixHeight(AVLTreeMapNode <TKey, TValue> node) { var leftHeight = NodeHeight(node.Left); var rightHeight = NodeHeight(node.Right); node.Height = (leftHeight > rightHeight ? leftHeight : rightHeight) + 1; }
/// <summary> /// Checks if balancing is needed and performs it. /// </summary> private AVLTreeMapNode <TKey, TValue> Balance(AVLTreeMapNode <TKey, TValue> node) { FixHeight(node); // if balance factor is -2 the left subtree is smaller than the right // so we need to perform a left rotation if (BalanceFactor(node) == -2) { if (BalanceFactor(node.Right) > 0)// Right Left Case if true, else Right Right Case { node.Right = RotateRight(node.Right); } return(RotateLeft(node)); } // if balance factor is 2 the right subtree is smaller than the left // so we need to perform a right rotation if (BalanceFactor(node) == 2) { if (BalanceFactor(node.Left) < 0)// Left Right Case if true, else Left Left Case { node.Left = RotateLeft(node.Left); } return(RotateRight(node)); } return(node); }
/// <summary> /// Finds and removes the min element of the given subtree. /// </summary> private AVLTreeMapNode <TKey, TValue> FindAndRemoveMin(AVLTreeMapNode <TKey, TValue> node, ref AVLTreeMapNode <TKey, TValue> min) { if (node.Left == null) { min = node; return(node.Right); } node.Left = FindAndRemoveMin(node.Left, ref min); return(Balance(node)); }
/// <summary> /// Standard right rotation. /// </summary> private AVLTreeMapNode <TKey, TValue> RotateRight(AVLTreeMapNode <TKey, TValue> node) { AVLTreeMapNode <TKey, TValue> m = node.Left; node.Left = m.Right; m.Right = node; FixHeight(node); FixHeight(m); return(m); }
/// <summary> /// Recursive removal with balancing on every step. /// </summary> private AVLTreeMapNode <TKey, TValue> Remove(AVLTreeMapNode <TKey, TValue> node, TKey key) { if (node == null) { return(node); } int cmp = comparer.Compare(key, node.Key); if (cmp < 0) { node.Left = Remove(node.Left, key); } else if (cmp > 0) { node.Right = Remove(node.Right, key); } else { Count--; AVLTreeMapNode <TKey, TValue> left = node.Left; AVLTreeMapNode <TKey, TValue> right = node.Right; node.Invalidate(); if (right == null) { return(left); } AVLTreeMapNode <TKey, TValue> min = null; AVLTreeMapNode <TKey, TValue> rightSubtreeRoot = FindAndRemoveMin(right, ref min); min.Right = rightSubtreeRoot; min.Left = left; return(Balance(min)); } return(Balance(node)); }
/// <summary> /// Recursive insertion with balancing on every step. /// </summary> private AVLTreeMapNode <TKey, TValue> Add(AVLTreeMapNode <TKey, TValue> node, TKey key, TValue value) { if (node == null) { return(new AVLTreeMapNode <TKey, TValue>(key, value)); } int cmp = comparer.Compare(key, node.Key); if (cmp < 0) { node.Left = Add(node.Left, key, value); } else if (cmp > 0) { node.Right = Add(node.Right, key, value); } else { throw new ArgumentException("Tried to insert duplicate value!"); } return(Balance(node)); }
/// <summary> /// Gets the node height. Returns 0 if node is null. /// </summary> private int NodeHeight(AVLTreeMapNode <TKey, TValue> node) { return(node?.Height ?? 0); }
/// <summary> /// Calculates the balance factor. /// </summary> private int BalanceFactor(AVLTreeMapNode <TKey, TValue> node) { return(NodeHeight(node.Left) - NodeHeight(node.Right)); }