using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace Advanced.Algorithms.DataStructures; /// /// A binary search tree implementation. /// public class Bst : IEnumerable where T : IComparable { public Bst() { } /// /// Initialize the BST with given sorted keys. /// Time complexity: O(n). /// public Bst(IEnumerable sortedCollection) : this() { BstHelpers.ValidateSortedCollection(sortedCollection); var nodes = sortedCollection.Select(x => new BstNode(null, x)).ToArray(); Root = (BstNode)BstHelpers.ToBst(nodes); BstHelpers.AssignCount(Root); } internal BstNode Root { get; set; } public int Count => Root == null ? 0 : Root.Count; //Implementation for the GetEnumerator method. IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public IEnumerator GetEnumerator() { return new BstEnumerator(Root); } /// /// Time complexity: O(n) /// public bool HasItem(T value) { if (Root == null) return false; return Find(Root, value) != null; } /// /// Time complexity: O(n) /// internal int GetHeight() { return GetHeight(Root); } //worst O(n) for unbalanced tree private int GetHeight(BstNode node) { if (node == null) return -1; return Math.Max(GetHeight(node.Left), GetHeight(node.Right)) + 1; } internal BstNode InsertAndReturnNewNode(T value) { if (Root == null) { Root = new BstNode(null, value); return Root; } var newNode = Insert(Root, value); return newNode; } /// /// Time complexity: O(n) /// public void Insert(T value) { if (Root == null) { Root = new BstNode(null, value); return; } var newNode = Insert(Root, value); newNode.UpdateCounts(true); } //worst O(n) for unbalanced tree private BstNode Insert(BstNode currentNode, T newNodeValue) { while (true) { var compareResult = currentNode.Value.CompareTo(newNodeValue); //current node is less than new item if (compareResult < 0) { //no right child if (currentNode.Right != null) { currentNode = currentNode.Right; continue; } //insert currentNode.Right = new BstNode(currentNode, newNodeValue); return currentNode.Right; } //current node is greater than new node if (compareResult > 0) { if (currentNode.Left == null) { //insert currentNode.Left = new BstNode(currentNode, newNodeValue); return currentNode.Left; } currentNode = currentNode.Left; } else { throw new Exception("Item exists"); } } } // /// Time complexity: O(n) /// public int IndexOf(T item) { return Root.Position(item); } /// /// Time complexity: O(n) /// public T ElementAt(int index) { if (index < 0 || index >= Count) throw new ArgumentNullException("index"); return Root.KthSmallest(index).Value; } /// /// Time complexity: O(n) /// public void Delete(T value) { if (Root == null) throw new Exception("Empty BST"); var deleted = Delete(Root, value); deleted.UpdateCounts(true); } /// /// Time complexity: O(n) /// public T RemoveAt(int index) { if (index < 0 || index >= Count) throw new ArgumentException("index"); var nodeToDelete = Root.KthSmallest(index) as BstNode; var deleted = Delete(nodeToDelete, nodeToDelete.Value); deleted.UpdateCounts(true); return nodeToDelete.Value; } //worst O(n) for unbalanced tree private BstNode Delete(BstNode node, T value) { while (true) { if (node != null) { var compareResult = node.Value.CompareTo(value); //node is less than the search value so move right to find the deletion node if (compareResult < 0) { node = node.Right ?? throw new Exception("Item do not exist"); continue; } //node is less than the search value so move left to find the deletion node if (compareResult > 0) { node = node.Left ?? throw new Exception("Item do not exist"); continue; } } if (node == null) return null; //node is a leaf node if (node.IsLeaf) { DeleteLeaf(node); return node; } //case one - right tree is null (move sub tree up) if (node.Left != null && node.Right == null) { DeleteLeftNode(node); return node; } //case two - left tree is null (move sub tree up) if (node.Right != null && node.Left == null) { DeleteRightNode(node); return node; } //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 var maxLeftNode = FindMax(node.Left); node.Value = maxLeftNode.Value; //delete left max node node = node.Left; value = maxLeftNode.Value; } } private void DeleteLeaf(BstNode node) { //if node is root if (node.Parent == null) Root = null; //assign nodes parent.left/right to null else if (node.IsLeftChild) node.Parent.Left = null; else node.Parent.Right = null; } private void DeleteRightNode(BstNode node) { //root if (node.Parent == null) { Root.Right.Parent = null; Root = Root.Right; } else { //node is left child of parent if (node.IsLeftChild) node.Parent.Left = node.Right; //node is right child of parent else node.Parent.Right = node.Right; node.Right.Parent = node.Parent; } } private void DeleteLeftNode(BstNode node) { //root if (node.Parent == null) { Root.Left.Parent = null; Root = Root.Left; } else { //node is left child of parent if (node.IsLeftChild) node.Parent.Left = node.Left; //node is right child of parent else node.Parent.Right = node.Left; node.Left.Parent = node.Parent; } } /// /// Time complexity: O(n) /// public T FindMax() { return FindMax(Root).Value; } private BstNode FindMax(BstNode node) { while (true) { if (node.Right == null) return node; node = node.Right; } } /// /// Time complexity: O(n) /// public T FindMin() { return FindMin(Root).Value; } private BstNode FindMin(BstNode node) { while (true) { if (node.Left == null) return node; node = node.Left; } } //find the node with the given identifier among descendants of parent and parent //uses pre-order traversal //worst O(n) for unbalanced tree internal BstNode FindNode(T value) { return Find(Root, value); } //find the node with the given identifier among descendants of parent and parent //uses pre-order traversal //worst O(n) for unbalanced tree private BstNode Find(BstNode parent, T value) { while (true) { if (parent == null) return null; if (parent.Value.CompareTo(value) == 0) return parent; var left = Find(parent.Left, value); if (left != null) return left; parent = parent.Right; } } //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 BstNodeBase Find(T value) { return Root.Find(value).Item1; } /// /// Get the next lower value to given value in this BST. /// Time complexity: O(n) /// public T NextLower(T value) { var node = Find(value); if (node == null) return default; var next = node.NextLower(); return next != null ? next.Value : default; } /// /// Get the next higher value to given value in this BST. /// Time complexity: O(n) /// public T NextHigher(T value) { var node = Find(value); if (node == null) return default; var next = node.NextHigher(); return next != null ? next.Value : default; } /// /// Descending enumerable. /// public IEnumerable AsEnumerableDesc() { return GetEnumeratorDesc().AsEnumerable(); } public IEnumerator GetEnumeratorDesc() { return new BstEnumerator(Root, false); } } internal class BstNode : BstNodeBase where T : IComparable { internal BstNode(BstNode parent, T value) { Parent = parent; Value = value; } internal new BstNode Parent { get => (BstNode)base.Parent; set => base.Parent = value; } internal new BstNode Left { get => (BstNode)base.Left; set => base.Left = value; } internal new BstNode Right { get => (BstNode)base.Right; set => base.Right = value; } }