using System; using System.Collections; namespace CornedBee.Utility { /// /// This class is a tree node for the tree. /// internal class TreeNode { /// /// The parent node. /// internal TreeNode parent = null; /// /// The left child node. /// internal TreeNode left = null; /// /// The right child node. /// internal TreeNode right = null; /// /// The height of this node's subtree. /// internal int height; /// /// The data. For dictionary trees, this is a KeyValuePair. /// internal object data; internal IComparable DataComp { get { return (IComparable)data; } } internal TreeNode(object d) { data = d; } } /// /// This class is a balanced binary tree. /// internal class BinaryTree : System.Collections.ICollection { /// /// Test Main for this class. /// /// Command line arguments. private class TreeEnumerator : IEnumerator { private BinaryTree tree; private TreeNode node; public TreeEnumerator(BinaryTree t) { tree = t; Reset(); } #region IEnumerator Members public void Reset() { node = null; } public object Current { get { return node.data; } } public bool MoveNext() { if(node == null) { if(tree.root == null) { return false; } else { node = tree.Minimum(tree.root); return true; } } else { node = tree.Next(node); return node != null; } } #endregion } private TreeNode root = null; private int count = 0; public BinaryTree() { } /// /// Gets the minimum node in n's subtree. /// /// The local root node. /// The node with the smallest value. internal TreeNode Minimum(TreeNode n) { while(n.left != null) { n = n.left; } return n; } /// /// Gets the maximum node in n's subtree. /// /// The local root node. /// The node with the largest value. internal TreeNode Maximum(TreeNode n) { while(n.right != null) { n = n.right; } return n; } /// /// Returns the next node in in-order traversal. /// /// The current node. /// The node with the next largest value. internal TreeNode Next(TreeNode n) { if(n.right != null) { return Minimum(n.right); } else { TreeNode t = n.parent; while(t != null && n == t.right) { n = t; t = t.parent; } return t; } } /// /// Returns the previous node in in-order traversal. /// /// The current node. /// The node with the next smallest value. internal TreeNode Previous(TreeNode n) { if(n.left != null) { return Maximum(n.left); } else { TreeNode t = n.parent; while(t != null && n == t.left) { n = t; t = t.parent; } return t; } } /// /// Recalculates the height of a node. /// /// The node for which to recalculate the height. private void AdjustHeight(TreeNode node) { int lw = node.left == null ? -1 : node.left.height; int rw = node.right == null ? -1 : node.right.height; node.height = Math.Max(lw, rw) + 1; } /// /// Helper method for rebalancing. Does a right rotation. /// /// On entry the unbalanced node. On exit the node in its place. private void RotateRight(ref TreeNode node) { TreeNode t = node.left; node.left = t.right; if(node.left != null) node.left.parent = node; t.right = node; if(t.right != null) t.right.parent = t; t.parent = node.parent; AdjustHeight(node); AdjustHeight(t); node = t; } /// /// Helper method for rebalancing. Does a left-right rotation. /// /// On entry the unbalanced node. On exit the node in its place. private void RotateLeftRight(ref TreeNode node) { RotateLeft(ref node.left); RotateRight(ref node); } /// /// Helper method for rebalancing. Does a left rotation. /// /// On entry the unbalanced node. On exit the node in its place. private void RotateLeft(ref TreeNode node) { TreeNode t = node.right; node.right = t.left; if(node.right != null) node.right.parent = node; t.left = node; t.parent = node.parent; if(t.left != null) t.left.parent = t; AdjustHeight(node); AdjustHeight(t); node = t; } /// /// Helper method for rebalancing. Does a right-left rotation. /// /// On entry the unbalanced node. On exit the node in its place. private void RotateRightLeft(ref TreeNode node) { RotateRight(ref node.right); RotateLeft(ref node); } /// /// Recursive insertion of a node, including rebalancing. /// /// The new node. /// The insertion location. /// Whether the new node was passed to the left or the right. -1 is left, +1 right. 0 means this /// node has the same key as the new one. private int InternalAdd(TreeNode newN, ref TreeNode curN) { int comp = newN.DataComp.CompareTo(curN.data); if(comp < 0) { if(curN.left == null) { curN.left = newN; newN.parent = curN; ++count; } else { int subcomp = InternalAdd(newN, ref curN.left); if(curN.right == null || curN.left.height - curN.right.height == 2) { if(subcomp < 0) { RotateRight(ref curN); } else { RotateLeftRight(ref curN); } } } } else if(comp > 0) { if(curN.right == null) { curN.right = newN; newN.parent = curN; ++count; } else { int subcomp = InternalAdd(newN, ref curN.right); if(curN.left == null || curN.right.height - curN.left.height == 2) { if(subcomp > 0) { RotateLeft(ref curN); } else { RotateRightLeft(ref curN); } } } } else { return 0; } AdjustHeight(curN); return comp; } /// /// Finds the node that contains value. /// /// The value of the node to be found. /// The node, or null. private TreeNode FindNode(object value) { TreeNode n = root; while(n != null) { int comp = n.DataComp.CompareTo(value); if(comp == 0) { break; } else if(comp < 0) { n = n.right; } else { n = n.left; } } return n; } /// /// Finds the balance of a node. The balance is the difference between /// the left and the right subheights. /// /// The node. /// The balance. Positive means the right tree is heavier. private int Balance(TreeNode n) { int lh = n.left != null ? n.left.height : -1; int rh = n.right != null ? n.right.height : -1; return rh - lh; } /// /// Re-establishes the tree balance after a deletion. /// /// The current node to rebalance. private void Rebalance(ref TreeNode n) { int bal = Balance(n); if(bal <= -2) { // Unbalanced to the left. int subbal = Balance(n.left); if(subbal < 0) { // Subtree leans left RotateRight(ref n); } else { // Subtree leans right RotateLeftRight(ref n); } } else if(bal >= 2) { // Unbalanced to the right. int subbal = Balance(n.right); if(subbal < 0) { // Subtree leans left RotateRightLeft(ref n); } else { // Subtree leans right RotateLeft(ref n); } } // Balance parent. if(n.parent != null) Rebalance(ref n.parent); else root = n; } #region ICollection Members public bool IsSynchronized { get { return false; } } public int Count { get { return count; } } public void CopyTo(Array array, int index) { throw new NotImplementedException(); } public object SyncRoot { get { throw new NotImplementedException(); } } #endregion #region IEnumerable Members public IEnumerator GetEnumerator() { return new TreeEnumerator(this); } #endregion internal object Get(object value) { TreeNode n = FindNode(value); if(n != null) return n.data; return null; } public void Remove(object value) { TreeNode n = FindNode(value); if(n != null) { --count; TreeNode r; if(n.left == null || n.right == null) { r = n; } else { r = Next(n); n.data = r.data; } n = (r.left == null) ? r.right : r.left; if(n != null) n.parent = r.parent; if(r.parent == null) { root = n; } else { if(r == r.parent.left) r.parent.left = n; else r.parent.right = n; } // Node unlinked, GC will collect it. // Now rebalance the tree. // r.parent might be null, but then the tree contained only one or two elements. // Which means it doesn't need rebalancing anyway. if(r.parent != null) { Rebalance(ref r.parent); } } } public bool Contains(object value) { return FindNode(value) != null; } public void Clear() { // This should suffice. root = null; } public void Add(object value) { TreeNode n = new TreeNode(value); if(root == null) { root = n; ++count; } else { InternalAdd(n, ref root); } } } /// /// A set is a collection that is optimized for fast "Contains" calls. /// public interface ISet : ICollection { /// /// Adds an object to the set. /// /// The value to add. public void Add(object value); /// /// Removes an object from the set. Does nothing if /// the value isn't in the set. /// /// The value to remove. public void Remove(object value); /// /// Tests if an object is in the set. /// /// The value to look for. /// True if the object is in the set. public bool Contains(object value); /// /// Completly clears the set. /// public void Clear(); } /// /// An implementation of ISet based on a binary tree. /// Contains performance is O(log n). /// public class TreeSet : ISet { BinaryTree impl = new BinaryTree(); IComparer comp; internal class DataWrapper : IComparable { internal IComparer comparer; internal object data; public DataWrapper(object value, IComparer comp) { data = value; comparer = comp; if(comparer == null) comparer = Comparer.Default; } #region IComparable Members public int CompareTo(object obj) { if(!(obj is DataWrapper)) throw new ArgumentException("Not a DataWrapper", "obj"); DataWrapper wrap = (DataWrapper)obj; return comparer.Compare(data, wrap.data); } #endregion } internal class EnumWrapper : IEnumerator { private IEnumerator inner; public EnumWrapper(IEnumerator e) { inner = e; } #region IEnumerator Members public void Reset() { inner.Reset(); } public object Current { get { DataWrapper wrap = (DataWrapper)inner.Current; return wrap.data; } } public bool MoveNext() { return inner.MoveNext(); } #endregion } /// /// Creates a new TreeSet. /// public TreeSet() { comp = null; } /// /// Creates a new TreeSet using a custom comparer. /// /// The comparer to use for sorting. public TreeSet(IComparer c) { comp = c; } #region ISet Members public void Add(object value) { impl.Add(new DataWrapper(value, comp)); } public void Remove(object value) { impl.Remove(new DataWrapper(value, comp)); } public bool Contains(object value) { return impl.Contains(new DataWrapper(value, comp)); } public void Clear() { impl.Clear(); } #endregion #region ICollection Members public bool IsSynchronized { get { return false; } } public int Count { get { return impl.Count; } } public void CopyTo(Array array, int index) { throw new NotImplementedException(); } public object SyncRoot { get { throw new NotImplementedException(); } } #endregion #region IEnumerable Members public IEnumerator GetEnumerator() { return new EnumWrapper(impl.GetEnumerator()); } #endregion } /// /// Binary-Tree-based dictionary. /// public class TreeDictionary : IDictionary { BinaryTree impl = new BinaryTree(); IComparer comp; public TreeDictionary() { comp = Comparer.Default; } public TreeDictionary(IComparer c) { comp = c; } public class KeyValuePair : DictionaryEntry, IComparable { internal object key; internal object value; internal IComparer comp; public KeyValuePair(object k, object v) { comp = Comparer.Default; key = k; value = v; } public KeyValuePair(object k, object v, IComparer comp) { this.comp = comp; key = k; value = v; } public object Key { get { return key; } set { throw new NotSupportedException("Keys cannot be modified."); } } public object Value { get { return value; } set { this.value = value; } } #region IComparable Members public int CompareTo(object obj) { if(!(obj is KeyValuePair)) throw new ArgumentException("not a KeyValuePair", "obj"); KeyValuePair kvp = (KeyValuePair)obj; return comp.Compare(key, kvp.key); } #endregion } internal class DictEnum : IDictionaryEnumerator { internal IEnumerator inner; public DictEnum(IEnumerator e) { inner = e; } #region IDictionaryEnumerator Members internal KeyValuePair Get() { return (KeyValuePair)inner.Current; } public object Key { get { return Get().Key; } } public object Value { get { return Get().Value; } } public DictionaryEntry Entry { get { return Get(); } } #endregion #region IEnumerator Members public void Reset() { inner.Reset(); } public object Current { get { return Entry; } } public bool MoveNext() { return inner.MoveNext(); } #endregion } #region IDictionary Members public bool IsReadOnly { get { return false; } } public IDictionaryEnumerator GetEnumerator() { return new DictEnum(impl.GetEnumerator()); } public object this[object key] { get { object o = impl.Get(new KeyValuePair(key, null, comp)); if(o == null) return null; return ((KeyValuePair)o).Value; } set { object o = impl.Get(new KeyValuePair(key, null, comp)); if(o == null) { impl.Add(new KeyValuePair(key, value, comp)); } else { ((KeyValuePair)o).Value = value; } } } public void Remove(object key) { impl.Remove(new KeyValuePair(key, null, comp)); } public bool Contains(object key) { return impl.Contains(new KeyValuePair(key, null, comp)); } public void Clear() { impl.Clear(); } public ICollection Values { get { throw new NotImplementedException(); } } public void Add(object key, object value) { impl.Add(new KeyValuePair(key, value, comp)); } public ICollection Keys { get { throw new NotImplementedException(); } } public bool IsFixedSize { get { return false; } } #endregion #region ICollection Members public bool IsSynchronized { get { return false; } } public int Count { get { return impl.Count; } } public void CopyTo(Array array, int index) { throw new NotImplementedException(); } public object SyncRoot { get { throw new NotImplementedException(); } } #endregion #region IEnumerable Members IEnumerator System.Collections.IEnumerable.GetEnumerator() { return new DictEnum(impl.GetEnumerator()); } #endregion } }