using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace Advanced.Algorithms.DataStructures { /// /// An AVL tree implementation. /// public class AVLTree : IEnumerable where T : IComparable { private readonly Dictionary> nodeLookUp; internal AVLTreeNode Root { get; set; } public int Count => Root == null ? 0 : Root.Count; /// Enabling lookup will fasten deletion/insertion/exists operations /// at the cost of additional space. public AVLTree(bool enableNodeLookUp = false) { if (enableNodeLookUp) { nodeLookUp = new Dictionary>(); } } /// /// Initialize the BST with given sorted keys. /// Time complexity: O(n). /// /// The initial sorted collection. /// Enabling lookup will fasten deletion/insertion/exists operations /// at the cost of additional space. public AVLTree(IEnumerable sortedCollection, bool enableNodeLookUp = false) { BSTHelpers.ValidateSortedCollection(sortedCollection); var nodes = sortedCollection.Select(x => new AVLTreeNode(null, x)).ToArray(); Root = (AVLTreeNode)BSTHelpers.ToBST(nodes); recomputeHeight(Root); BSTHelpers.AssignCount(Root); if (enableNodeLookUp) { nodeLookUp = nodes.ToDictionary(x => x.Value, x => x as BSTNodeBase); } } /// /// Time complexity: O(log(n)) /// public bool HasItem(T value) { if (Root == null) { return false; } return find(Root, value) != null; } /// /// Time complexity: O(log(n)) /// internal int GetHeight() { if (Root == null) return -1; return Root.Height; } /// /// Time complexity: O(log(n)) /// public void Insert(T value) { if (Root == null) { Root = new AVLTreeNode(null, value); if (nodeLookUp != null) { nodeLookUp[value] = Root; } return; } insert(Root, value); } /// /// Time complexity: O(log(n)) /// private void insert(AVLTreeNode node, T value) { var compareResult = node.Value.CompareTo(value); //node is less than the value so move right for insertion if (compareResult < 0) { if (node.Right == null) { node.Right = new AVLTreeNode(node, value); if (nodeLookUp != null) { nodeLookUp[value] = node.Right; } } else { insert(node.Right, value); } } //node is greater than the value so move left for insertion else if (compareResult > 0) { if (node.Left == null) { node.Left = new AVLTreeNode(node, value); if (nodeLookUp != null) { nodeLookUp[value] = node.Left; } } else { insert(node.Left, value); } } else { throw new Exception("Item exists"); } updateHeight(node); balance(node); node.UpdateCounts(); } /// /// Time complexity: O(log(n)) /// public int IndexOf(T item) { return Root.Position(item); } /// /// Time complexity: O(log(n)) /// public T ElementAt(int index) { if (index < 0 || index >= Count) { throw new ArgumentNullException("index"); } return Root.KthSmallest(index).Value; } /// /// Time complexity: O(log(n)). /// public void Delete(T value) { if (Root == null) { throw new Exception("Empty AVLTree"); } delete(Root, value); if (nodeLookUp != null) { nodeLookUp.Remove(value); } } /// /// Time complexity: O(log(n)) /// public T RemoveAt(int index) { if (index < 0 || index >= Count) { throw new ArgumentException("index"); } var nodeToDelete = Root.KthSmallest(index) as AVLTreeNode; var nodeToBalance = delete(nodeToDelete, nodeToDelete.Value); while (nodeToBalance != null) { nodeToBalance.UpdateCounts(); updateHeight(nodeToBalance); balance(nodeToBalance); nodeToBalance = nodeToBalance.Parent; } if (nodeLookUp != null) { nodeLookUp.Remove(nodeToDelete.Value); } return nodeToDelete.Value; } private AVLTreeNode delete(AVLTreeNode node, T value) { var baseCase = false; var compareResult = node.Value.CompareTo(value); //node is less than the search value so move right to find the deletion node if (compareResult < 0) { if (node.Right == null) { throw new Exception("Item do not exist"); } delete(node.Right, value); } //node is less than the search value so move left to find the deletion node else if (compareResult > 0) { if (node.Left == null) { throw new Exception("Item do not exist"); } delete(node.Left, value); } else { //node is a leaf node if (node.IsLeaf) { //if node is root if (node.Parent == null) { Root = null; } //assign nodes parent.left/right to null else if (node.Parent.Left == node) { node.Parent.Left = null; } else { node.Parent.Right = null; } baseCase = true; } else { //case one - right tree is null (move sub tree up) if (node.Left != null && node.Right == null) { //root if (node.Parent == null) { Root.Left.Parent = null; Root = Root.Left; } else { //node is left child of parent if (node.Parent.Left == node) { node.Parent.Left = node.Left; } //node is right child of parent else { node.Parent.Right = node.Left; } node.Left.Parent = node.Parent; } baseCase = true; } //case two - left tree is null (move sub tree up) else if (node.Right != null && node.Left == null) { //root if (node.Parent == null) { Root.Right.Parent = null; Root = Root.Right; } else { //node is left child of parent if (node.Parent.Left == node) { node.Parent.Left = node.Right; } //node is right child of parent else { node.Parent.Right = node.Right; } node.Right.Parent = node.Parent; } baseCase = true; } //case three - two child trees //replace the node value with maximum element of left subtree (left max node) //and then delete the left max node else { var maxLeftNode = findMax(node.Left); node.Value = maxLeftNode.Value; if (nodeLookUp != null) { nodeLookUp[node.Value] = node; } //delete left max node delete(node.Left, maxLeftNode.Value); } } } if (baseCase) { node.Parent.UpdateCounts(); updateHeight(node.Parent); balance(node.Parent); return node.Parent; } else { node.UpdateCounts(); updateHeight(node); balance(node); return node; } } /// /// Time complexity: O(log(n)). /// public T FindMax() { return findMax(Root).Value; } private AVLTreeNode findMax(AVLTreeNode node) { while (true) { if (node.Right == null) { return node; } node = node.Right; } } /// /// Time complexity: O(log(n)). /// public T FindMin() { return findMin(Root).Value; } private AVLTreeNode findMin(AVLTreeNode node) { while (true) { if (node.Left == null) { return node; } node = node.Left; } } /// /// Time complexity: O(log(n)). /// public bool Contains(T value) { if (Root == null) { return false; } return find(Root, value) != null; } //find the node with the given identifier among descendants of parent and parent //uses pre-order traversal //O(log(n)) worst O(n) for unbalanced tree private AVLTreeNode find(T value) { if (nodeLookUp != null) { return nodeLookUp[value] as AVLTreeNode; } return Root.Find(value).Item1 as AVLTreeNode; } //find the node with the given identifier among descendants of parent and parent //uses pre-order traversal //O(log(n)) worst O(n) for unbalanced tree private AVLTreeNode find(AVLTreeNode parent, T value) { if (parent == null) { return null; } if (parent.Value.CompareTo(value) == 0) { return parent; } var left = find(parent.Left, value); if (left != null) { return left; } var right = find(parent.Right, value); return right; } private void balance(AVLTreeNode node) { if (node == null) return; if (node.Left == null && node.Right == null) return; var leftHeight = node.Left?.Height + 1 ?? 0; var rightHeight = node.Right?.Height + 1 ?? 0; var balanceFactor = leftHeight - rightHeight; //tree is left heavy //differance >=2 then do rotations if (balanceFactor >= 2) { leftHeight = node.Left?.Left?.Height + 1 ?? 0; rightHeight = node.Left?.Right?.Height + 1 ?? 0; //left child is left heavy if (leftHeight > rightHeight) { rightRotate(node); } //left child is right heavy else { leftRotate(node.Left); rightRotate(node); } } //tree is right heavy //differance <=-2 then do rotations else if (balanceFactor <= -2) { leftHeight = node.Right?.Left?.Height + 1 ?? 0; rightHeight = node.Right?.Right?.Height + 1 ?? 0; //right child is right heavy if (rightHeight > leftHeight) { leftRotate(node); } //right child is left heavy else { rightRotate(node.Right); leftRotate(node); } } } private void rightRotate(AVLTreeNode node) { var prevRoot = node; var leftRightChild = prevRoot.Left.Right; var newRoot = node.Left; //make left child as root prevRoot.Left.Parent = prevRoot.Parent; if (prevRoot.Parent != null) { if (prevRoot.Parent.Left == prevRoot) { prevRoot.Parent.Left = prevRoot.Left; } else { prevRoot.Parent.Right = prevRoot.Left; } } //move prev root as right child of current root newRoot.Right = prevRoot; prevRoot.Parent = newRoot; //move right child of left child of prev root to left child of right child of new root newRoot.Right.Left = leftRightChild; if (newRoot.Right.Left != null) { newRoot.Right.Left.Parent = newRoot.Right; } updateHeight(newRoot); newRoot.Left.UpdateCounts(); newRoot.Right.UpdateCounts(); newRoot.UpdateCounts(); if (prevRoot == Root) { Root = newRoot; } } private void leftRotate(AVLTreeNode node) { var prevRoot = node; var rightLeftChild = prevRoot.Right.Left; var newRoot = node.Right; //make right child as root prevRoot.Right.Parent = prevRoot.Parent; if (prevRoot.Parent != null) { if (prevRoot.Parent.Left == prevRoot) { prevRoot.Parent.Left = prevRoot.Right; } else { prevRoot.Parent.Right = prevRoot.Right; } } //move prev root as left child of current root newRoot.Left = prevRoot; prevRoot.Parent = newRoot; //move left child of right child of prev root to right child of left child of new root newRoot.Left.Right = rightLeftChild; if (newRoot.Left.Right != null) { newRoot.Left.Right.Parent = newRoot.Left; } updateHeight(newRoot); newRoot.Left.UpdateCounts(); newRoot.Right.UpdateCounts(); newRoot.UpdateCounts(); if (prevRoot == Root) { Root = newRoot; } } private void updateHeight(AVLTreeNode node) { if (node == null) { return; } if (node.Left != null) { node.Left.Height = Math.Max(node.Left.Left?.Height + 1 ?? 0, node.Left.Right?.Height + 1 ?? 0); } if (node.Right != null) { node.Right.Height = Math.Max(node.Right.Left?.Height + 1 ?? 0, node.Right.Right?.Height + 1 ?? 0); } node.Height = Math.Max(node.Left?.Height + 1 ?? 0, node.Right?.Height + 1 ?? 0); } private void recomputeHeight(AVLTreeNode node) { if (node == null) { return; } recomputeHeight(node.Left); recomputeHeight(node.Right); updateHeight(node); } /// /// Get the next lower value to given value in this BST. /// Time complexity: O(log(n)) /// public T NextLower(T value) { var node = find(value); if (node == null) { return default(T); } var next = (node as BSTNodeBase).NextLower(); return next != null ? next.Value : default(T); } /// /// Get the next higher value to given value in this BST. /// Time complexity: O(log(n)) /// public T NextHigher(T value) { var node = find(value); if (node == null) { return default(T); } var next = (node as BSTNodeBase).NextHigher(); return next != null ? next.Value : default(T); } internal void Swap(T value1, T value2) { var node1 = find(value1); var node2 = find(value2); if (node1 == null || node2 == null) { throw new Exception("Value1, Value2 or both was not found in this BST."); } var tmp = node1.Value; node1.Value = node2.Value; node2.Value = tmp; if (nodeLookUp != null) { nodeLookUp[node1.Value] = node1; nodeLookUp[node2.Value] = node2; } } /// /// Descending enumerable. /// public IEnumerable AsEnumerableDesc() { return GetEnumeratorDesc().AsEnumerable(); } public IEnumerator GetEnumeratorDesc() { return new BSTEnumerator(Root, false); } //Implementation for the GetEnumerator method. IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public IEnumerator GetEnumerator() { return new BSTEnumerator(Root); } } internal class AVLTreeNode : BSTNodeBase where T : IComparable { internal new AVLTreeNode Parent { get { return (AVLTreeNode)base.Parent; } set { base.Parent = value; } } internal new AVLTreeNode Left { get { return (AVLTreeNode)base.Left; } set { base.Left = value; } } internal new AVLTreeNode Right { get { return (AVLTreeNode)base.Right; } set { base.Right = value; } } internal AVLTreeNode(AVLTreeNode parent, T value) { Parent = parent; Value = value; Height = 0; } internal int Height { get; set; } } }