using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace ln.collections { public class BTree : IDict { public Comparison Comparison { get; } public int Count => count; public bool Empty => count == 0; public int LeftDepth => headNode != null ? headNode.LeftDepth : 0; public int RightDepth => headNode != null ? headNode.RightDepth : 0; public int Depth => Math.Max(LeftDepth, RightDepth); public int LimBalance { get => limBalance; set { if (value == 0) throw new ArgumentException(nameof(value)); limBalance = value; } } TreeNode headNode; private int count; private int limBalance; public BTree() { if (!typeof(K).GetInterfaces().Contains(typeof(IComparable))) { Comparison = (K x, K y) => x.GetHashCode() - y.GetHashCode(); } else { Comparison = (K x, K y) => ((IComparable)x).CompareTo(y); } } public BTree(Comparison comparison) { Comparison = comparison; } public V this[K key] { get { TreeNode node = Find(key); if (object.ReferenceEquals(node,null)) throw new KeyNotFoundException(); return node.Value; } set { TreeNode node = Find(key); if (object.ReferenceEquals(node, null)) { Add(key, value); } else { node.Value = value; } } } public Boolean TryGet(K key, out V value) { TreeNode node = Find(key); if (object.ReferenceEquals(node, null)) { value = default(V); return false; } value = node.Value; return true; } public virtual void Add(K key,V value) { TreeNode treeNode = new TreeNode(this, key, value); Insert(treeNode); count++; } public virtual void TryAdd(K key,V value) { TreeNode treeNode = Find(key); if (object.ReferenceEquals(treeNode, null)) Add(key, value); } public virtual void Remove(K key) { TreeNode node = Find(key); if (object.ReferenceEquals(node, null)) throw new KeyNotFoundException(); Remove(node); count--; } public virtual bool TryRemove(K key) { TreeNode node = Find(key); if (node != null) Remove(node); return node != null; } public bool ContainsKey(K key) { return Find(key) != null; } public bool ContainsValue(V value) { return Values.Contains(value); } public K GetKey(K key) { if (TryGetKey(key, out K storedKey)) return storedKey; throw new KeyNotFoundException(); } public bool TryGetKey(K key,out K storedKey) { TreeNode treeNode = Find(key); if (treeNode == null) { storedKey = default(K); return false; } else { storedKey = treeNode.Key; return true; } } public void Clear() { headNode = null; count = 0; } public K First() { TreeNode node = First(headNode); if (node != null) return node.Key; throw new KeyNotFoundException("BTree is empty"); } public V FirstValue() { TreeNode node = First(headNode); if (node != null) return node.Value; throw new KeyNotFoundException("BTree is empty"); } public bool TryGetFirstValue(out V value) { TreeNode node = First(headNode); if (node != null) { value = node.Value; return true; } value = default(V); return false; } public K Last() { TreeNode node = Last(headNode); if (node != null) return node.Key; throw new KeyNotFoundException("BTree is empty"); } public V LastValue() { TreeNode node = Last(headNode); if (node != null) return node.Value; throw new KeyNotFoundException("BTree is empty"); } public bool TryGetLastValue(out V value) { TreeNode node = Last(headNode); if (node != null) { value = node.Value; return true; } value = default(V); return false; } public K Previous(K current) { TreeNode node = Previous(Find(current)); if (node != null) return node.Key; throw new KeyNotFoundException(); } public bool TryGetPrevious(K current, out K previous) { TreeNode node = Previous(Find(current)); if (node != null) { previous = node.Key; return true; } previous = default(K); return false; } public bool TryGetPreviousValue(K current, out V previous) { TreeNode node = Previous(Find(current)); if (node != null) { previous = node.Value; return true; } previous = default(V); return false; } public K Next(K current) { TreeNode node = Next(Find(current)); if (node != null) return node.Key; throw new KeyNotFoundException(); } public bool TryGetNext(K current, out K next) { TreeNode node = Next(Find(current)); if (node != null) { next = node.Key; return true; } next = default(K); return false; } public bool TryGetNextValue(K current, out V next) { TreeNode node = Next(Find(current)); if (node != null) { next = node.Value; return true; } next = default(V); return false; } public K PreviousOrCurrent(K current) { if (!TryGetPreviousOrCurrent(current, out K previousOrCurrent)) throw new KeyNotFoundException(); return previousOrCurrent; } public bool TryGetPreviousOrCurrent(K current, out K previousOrCurrent) { if (Empty) { previousOrCurrent = default(K); return false; } TreeNode next = FindFirstGE(current); if (next == null) previousOrCurrent = Last(); else previousOrCurrent = Previous(next).Key; return true; } public bool TryGetPreviousOrCurrentValue(K current, out V previousOrCurrentValue) { if (Empty) { previousOrCurrentValue = default(V); return false; } TreeNode next = FindFirstGE(current); if (next == null) previousOrCurrentValue = LastValue(); else { TreeNode previousNode = Previous(next); if (previousNode == null) previousOrCurrentValue = FirstValue(); else previousOrCurrentValue = previousNode.Value; } return true; } private TreeNode First(TreeNode node) { if (object.ReferenceEquals(node, null)) return null; while (node.Left != null) node = node.Left; return node; } private TreeNode Last(TreeNode node) { if (object.ReferenceEquals(node, null)) return null; while (node.Right != null) node = node.Right; return node; } private TreeNode Find(K key) { TreeNode node = headNode; while (node != null) { int comp = Comparison(key, node.Key); if (comp == 0) return node; else if (comp < 0) node = node.Left; else node = node.Right; } return null; } private TreeNode FindFirstGE(K key) { TreeNode node = headNode; TreeNode minNode = null; while (node != null) { if ((Comparison(node.Key, key) >= 0) && ((minNode == null) || (Comparison(node.Key, minNode.Key) < 0))) minNode = node; int comp = Comparison(key, node.Key); if (comp == 0) return node; else if (comp < 0) { if (node.Left == null) return minNode; node = node.Left; } else { if (node.Right == null) return minNode; node = node.Right; } } return null; } private TreeNode Previous(TreeNode node) { if (node.Left != null) return Last(node.Left); while (node != null) { if (object.ReferenceEquals(node.Parent, null)) return null; if (node.Parent.Right == node) return node.Parent; node = node.Parent; } return null; } private TreeNode Next(TreeNode node) { if (node.Right != null) return First(node.Right); while (node != null) { if (object.ReferenceEquals(node.Parent, null)) return null; if (node.Parent.Left == node) return node.Parent; node = node.Parent; } return null; } private void Insert(TreeNode newNode) { if (object.ReferenceEquals(headNode, null)) { headNode = newNode; } else { TreeNode node = headNode; while (true) { int c = Comparison(newNode.Key, node.Key); if (c == 0) { throw new ArgumentException("Key exists"); } else if (c < 0) { if (node.Left == null) { newNode.Attach(node); Balance(node.Parent); return; } else node = node.Left; } else { if (node.Right == null) { newNode.Attach(node); Balance(node.Parent); return; } else node = node.Right; } } } } private void Remove(TreeNode node) { TreeNode p = node.Parent; if ((node.Left != null) && (node.Right != null)) { TreeNode replace = Last(node.Left); TreeNode replaceParent = replace.Parent; if (replaceParent == node) { node.Detach(); node.Right.Attach(node.Left); node.Left.Attach(p); } else { TreeNode left = node.Left; TreeNode right = node.Right; node.Detach(); if (left != null) left.Detach(); if (right != null) right.Detach(); replace.Detach(); if (replace.Left != null) replace.Left.Attach(replaceParent); replace.Attach(p); if (left != null) left.Attach(replace); if (right != null) right.Attach(replace); } Balance(replace); } else { node.Detach(); if (node.Left != null) node.Left.Attach(p); else if (node.Right != null) node.Right.Attach(p); Balance(p); } } private void RotateRight(TreeNode node) { TreeNode l = node.Left; TreeNode p = node.Parent; node.Detach(); l.Attach(p); if (l.Right!= null) l.Right.Attach(node); node.Attach(l); } private void RotateLeft(TreeNode node) { TreeNode r = node.Right; TreeNode p = node.Parent; node.Detach(); r.Attach(p); if (r.Left != null) r.Left.Attach(node); node.Attach(r); } private void Balance(TreeNode node) { while (node != null) { TreeNode p = node.Parent; int myBalance = node.LeftDepth - node.RightDepth; if (myBalance + limBalance < 0) { RotateLeft(node); } else if (myBalance - limBalance > 0) { RotateRight(node); } node = p; } } public IEnumerable KeysFrom(K first) { TreeNode node = Find(first); while (node != null) { yield return node.Key; node = Next(node); } } public IEnumerable KeysGreaterEqual(K first) { TreeNode node = FindFirstGE(first); while (node != null) { yield return node.Key; node = Next(node); } } public void Add(object key, object value) => Add((K)key, (V)value); public void Remove(object key) => Remove((K)key); public bool ContainsKey(object key) => ContainsKey((K)key); public object this[object key] { get => this[(K)key]; set => this[(K)key] = (V)value; } public IEnumerable Keys { get { TreeNode node = First(headNode); while (node != null) { yield return node.Key; node = Next(node); } } } public IEnumerable Values { get { TreeNode node = First(headNode); while (node != null) { yield return node.Value; node = Next(node); } } } IEnumerable IDict.Keys => Keys; IEnumerable IDict.Values => Values; class TreeNode { public BTree Tree { get; } public K Key { get; private set; } public V Value { get; set; } public TreeNode Parent { get; private set; } public int Depth => 1 + Math.Max(LeftDepth, RightDepth); //public int LeftDepth => Left != null ? Left.Depth : 0; //public int RightDepth => Right != null ? Right.Depth : 0; public int LeftDepth => leftDepth; public int RightDepth => rightDepth; public TreeNode Left { get; private set; } public TreeNode Right { get; private set; } private int leftDepth = 0; private int rightDepth = 0; public TreeNode(BTree tree, K key, V value) { Tree = tree; Key = key; Value = value; } public void Attach(TreeNode parent) { if (!object.ReferenceEquals(this.Parent, null)) Detach(); if (parent == null) { Tree.headNode = this; Parent = null; } else { int comp = Tree.Comparison(Key, parent.Key); if (comp == 0) throw new ArgumentException(String.Format("Key already exists in BTree ({0})",Key)); else if (comp < 0) { if (parent.Left != null) throw new InvalidOperationException("Another Key is already attached to Parent (left)"); parent.Left = this; parent.leftDepth = Depth + 1; } else { if (parent.Right != null) throw new InvalidOperationException("Another Key is already attached to Parent (right)"); parent.Right = this; parent.rightDepth = Depth + 1; } Parent = parent; } } public void Detach() { if (this.Parent != null) { if (this.Parent.Left == this) { this.Parent.Left = null; this.Parent.leftDepth = 0; } else if (this.Parent.Right == this) { this.Parent.Right = null; this.Parent.rightDepth = 0; } Parent = null; } else if (Tree.headNode == this) { Tree.headNode = null; } } public override string ToString() { return String.Format("[TreeNode Key={0} Value={1}]",Key,Value); } } } public class BTree : BTree { public BTree() { } public BTree(Comparison comparison) :base(comparison) { } public void Add(K key) { Add(key, null); } public void TryAdd(K key) { TryAdd(key, null); } public void AddRange(IEnumerable keys) { foreach (K key in keys) { Add(key, null); } } public void TryAddRange(IEnumerable keys) { foreach (K key in keys) { TryAdd(key, null); } } } }