/* Copyright 2007-2013 The NGenerics Team (https://github.com/ngenerics/ngenerics/wiki/Team) This program is licensed under the GNU Lesser General Public License (LGPL). You should have received a copy of the license along with the source code. If not, an online copy of the license can be found at http://www.gnu.org/copyleft/lesser.html. */ using System; using System.Collections; using System.Collections.Generic; using NGenerics.Patterns.Visitor; using NGenerics.Util; using System.Diagnostics.CodeAnalysis; namespace NGenerics.DataStructures.Trees { /// /// An implementation of a Binary Tree data structure. /// /// The type of elements in the . //[Serializable] [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] public class BinaryTree : ICollection, ITree { #region Globals private BinaryTree leftSubtree; private BinaryTree rightSubtree; private T data; #endregion #region Construction /// The data contained in this node. public BinaryTree(T data) : this(data, null, null) { } /// The data. /// The data of the left subtree. /// The data of the right subtree. public BinaryTree(T data, T left, T right) : this(data, new BinaryTree(left), new BinaryTree(right)) { } /// The data contained in this node. /// The left subtree. /// The right subtree. public BinaryTree(T data, BinaryTree left, BinaryTree right) : this(data, left, right, true) { } /// The data contained in this node. /// The left subtree. /// The right subtree. /// to validate ; otherwise . internal BinaryTree(T data, BinaryTree left, BinaryTree right, bool validateData) { #region Validation //TODO: probably not the most efficient way of doing this but SplayTree needs to use a BinaryTree with null data. if (validateData) { Guard.ArgumentNotNull(data, "data"); } #endregion leftSubtree = left; if (left != null) { left.Parent = this; } rightSubtree = right; if (right != null) { right.Parent = this; } this.data = data; } #endregion #region ICollection Members /// public bool IsEmpty { get { return Count == 0; } } /// public bool IsFull { get { return (leftSubtree != null) && (rightSubtree != null); } } /// public bool Contains(T item) { foreach (var thisItem in this) { if (item.Equals(thisItem)) { return true; } } return false; } /// public void CopyTo(T[] array, int arrayIndex) { Guard.ArgumentNotNull(array, "array"); foreach (var item in this) { #region Validation if (arrayIndex >= array.Length) { throw new ArgumentException(Constants.NotEnoughSpaceInTheTargetArray, "array"); } #endregion array[arrayIndex++] = item; } } /// public int Count { get { var count = 0; if (leftSubtree != null) { count++; } if (rightSubtree != null) { count++; } return count; } } /// public void Add(T item) { AddItem(new BinaryTree(item)); } /// public bool Remove(T item) { if (leftSubtree != null) { if (leftSubtree.data.Equals(item)) { RemoveLeft(); return true; } } if (rightSubtree != null) { if (rightSubtree.data.Equals(item)) { RemoveRight(); return true; } } return false; } /// /// Removes the specified child. /// /// The child. /// A value indicating whether the child was found (and removed) from this tree. public bool Remove(BinaryTree child) { if (leftSubtree != null) { if (leftSubtree == child) { RemoveLeft(); return true; } } if (rightSubtree != null) { if (rightSubtree == child) { RemoveRight(); return true; } } return false; } /// /// Returns an enumerator that iterates through the collection. /// /// /// A that can be used to iterate through the collection. /// public IEnumerator GetEnumerator() { var stack = new Stack>(); stack.Push(this); while (stack.Count > 0) { var tree = stack.Pop(); yield return tree.Data; if (tree.leftSubtree != null) { stack.Push(tree.leftSubtree); } if (tree.rightSubtree != null) { stack.Push(tree.rightSubtree); } } } /// public virtual void Clear() { if (leftSubtree != null) { leftSubtree.Parent = null; leftSubtree = null; } if (rightSubtree != null) { rightSubtree.Parent = null; rightSubtree = null; } } #endregion #region ITree Members /// void ITree.Add(ITree child) { AddItem((BinaryTree)child); } /// ITree ITree.GetChild(int index) { return GetChild(index); } /// bool ITree.Remove(ITree child) { return Remove((BinaryTree)child); } /// ITree ITree.FindNode(Predicate condition) { return FindNode(condition); } /// ITree ITree.Parent { get { return Parent; } } #endregion #region Public Members /// /// Gets the parent of the current node.. /// /// The parent of the current node. public BinaryTree Parent { get; private set; } /// /// Finds the node with the specified condition. If a node is not found matching /// the specified condition, null is returned. /// /// The condition to test. /// The first node that matches the condition supplied. If a node is not found, null is returned. /// is a null reference (Nothing in Visual Basic). public BinaryTree FindNode(Predicate condition) { Guard.ArgumentNotNull(condition, "condition"); if (condition(Data)) { return this; } if (leftSubtree != null) { var ret = leftSubtree.FindNode(condition); if (ret != null) { return ret; } } if (rightSubtree != null) { var ret = rightSubtree.FindNode(condition); if (ret != null) { return ret; } } return null; } /// /// Gets or sets the left subtree. /// /// The left subtree. [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public virtual BinaryTree Left { get { return leftSubtree; } set { if (leftSubtree != null) { RemoveLeft(); } if (value != null) { if (value.Parent != null) { value.Parent.Remove(value); } value.Parent = this; } leftSubtree = value; } } /// /// Gets or sets the right subtree. /// /// The right subtree. [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public virtual BinaryTree Right { get { return rightSubtree; } set { if (rightSubtree != null) { RemoveRight(); } if (value != null) { if (value.Parent != null) { value.Parent.Remove(value); } value.Parent = this; } rightSubtree = value; } } /// public virtual T Data { get { return data; } set { #region Validation Guard.ArgumentNotNull(value, "data"); #endregion data = value; } } /// public int Degree { get { return Count; } } /// /// Gets the child at the specified index. /// /// The index of the child in question. /// The child at the specified index. /// does not equal 0 or 1. public BinaryTree GetChild(int index) { switch (index) { case 0: return leftSubtree; case 1: return rightSubtree; default: throw new ArgumentOutOfRangeException("index"); } } /// public virtual int Height { get { if (Degree == 0) { return 0; } return 1 + FindMaximumChildHeight(); } } /// /// Performs a depth first traversal on this tree with the specified visitor. /// /// The ordered visitor. /// is a null reference (Nothing in Visual Basic). public virtual void DepthFirstTraversal(OrderedVisitor orderedVisitor) { Guard.ArgumentNotNull(orderedVisitor, "orderedVisitor"); if (orderedVisitor.HasCompleted) { return; } // Preorder visit orderedVisitor.VisitPreOrder(Data); if (leftSubtree != null) { leftSubtree.DepthFirstTraversal(orderedVisitor); } // In-order visit orderedVisitor.VisitInOrder(data); if (rightSubtree != null) { rightSubtree.DepthFirstTraversal(orderedVisitor); } // PostOrder visit orderedVisitor.VisitPostOrder(Data); } /// /// Performs a breadth first traversal on this tree with the specified visitor. /// /// The visitor. /// is a null reference (Nothing in Visual Basic). public virtual void BreadthFirstTraversal(IVisitor visitor) { Guard.ArgumentNotNull(visitor, "visitor"); var queue = new Queue>(); queue.Enqueue(this); while (queue.Count > 0) { if (visitor.HasCompleted) { break; } var binaryTree = queue.Dequeue(); visitor.Visit(binaryTree.Data); for (var i = 0; i < binaryTree.Degree; i++) { var child = binaryTree.GetChild(i); if (child != null) { queue.Enqueue(child); } } } } /// public virtual bool IsLeafNode { get { return Degree == 0; } } /// /// Removes the left child. /// public virtual void RemoveLeft() { if (leftSubtree != null) { leftSubtree.Parent = null; leftSubtree = null; } } /// /// Removes the left child. /// public virtual void RemoveRight() { if (rightSubtree != null) { rightSubtree.Parent = null; rightSubtree = null; } } /// /// Adds an item to the . /// /// The subtree. /// The is read-only. /// The is full. /// is null (Nothing in Visual Basic). public void Add(BinaryTree subtree) { Guard.ArgumentNotNull(subtree, "subtree"); AddItem(subtree); } /// /// Adds an item to the . /// /// The subtree. /// /// Notes to Inheritors: /// Derived classes can override this method to change the behavior of the method. /// protected virtual void AddItem(BinaryTree subtree) { if (leftSubtree == null) { if (subtree.Parent != null) { subtree.Parent.Remove(subtree); } leftSubtree = subtree; subtree.Parent = this; } else if (rightSubtree == null) { if (subtree.Parent != null) { subtree.Parent.Remove(subtree); } rightSubtree = subtree; subtree.Parent = this; } else { throw new InvalidOperationException("This binary tree is full."); } } #endregion #region Private Members /// /// Finds the maximum height between the child nodes. /// /// The maximum height of the tree between all paths from this node and all leaf nodes. protected virtual int FindMaximumChildHeight() { var leftHeight = 0; var rightHeight = 0; if (leftSubtree != null) { leftHeight = leftSubtree.Height; } if (rightSubtree != null) { rightHeight = rightSubtree.Height; } return leftHeight > rightHeight ? leftHeight : rightHeight; } #endregion #region Operator Overloads /// /// Gets the at the specified index. /// public BinaryTree this[int index] { get { return GetChild(index); } } #endregion #region ICollection Members /// public bool IsReadOnly { get { return false; } } #endregion #region IEnumerable Members /// IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion #region Object Members /// public override string ToString() { return data.ToString(); } #endregion } }