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