/* 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.Comparers; using System.Diagnostics.CodeAnalysis; using NGenerics.Util; namespace NGenerics.DataStructures.General { /// /// An implementation of a Heap data structure. /// /// The type of item stored in the . //[Serializable] [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")] [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] public class Heap : ICollection, IHeap { #region Globals const string heapIsEmpty = "The heap is empty."; private readonly List data; private readonly IComparer comparerToUse; private readonly HeapType thisType; #endregion #region Construction /// /// Initializes a new instance of the class. /// /// The type of Heap to create. /// is not either or . /// /// /// /// public Heap(HeapType type) : this(type, Comparer.Default) { } /// /// Initializes a new instance of the class. /// /// The type of heap. /// The capacity. /// is not either or . /// is less than 0. /// . /// /// /// /// public Heap(HeapType type, int capacity) : this(type, capacity, Comparer.Default) { } /// /// Initializes a new instance of the class. /// /// The type of heap. /// The comparer. /// is not either or . public Heap(HeapType type, Comparison comparer) : this(type, new ComparisonComparer(comparer)){} /// /// Initializes a new instance of the class. /// /// The type of heap. /// The capacity of the heap to start with. /// The comparer. /// is not either or . /// is less than 0. public Heap(HeapType type, int capacity, Comparison comparer) : this(type, capacity, new ComparisonComparer(comparer)) { } /// /// Initializes a new instance of the class. /// /// The type of Heap to create. /// The comparer to use. /// is a null reference (Nothing in Visual Basic). /// is not either or . /// /// /// /// public Heap(HeapType type, IComparer comparer) { Guard.ArgumentNotNull(comparer, "comparer"); if ((type != HeapType.Minimum) && (type != HeapType.Maximum)) { throw new ArgumentOutOfRangeException("type"); } thisType = type; data = new List {default(T)}; comparerToUse = type == HeapType.Minimum ? comparer : new ReverseComparer(comparer); } /// The type of heap. /// The initial capacity of the Heap. /// The comparer to use. /// is less than 0.. /// is a null reference (Nothing in Visual Basic). /// is not either or . public Heap(HeapType type, int capacity, IComparer comparer) { Guard.ArgumentNotNull(comparer, "comparer"); if ((type != HeapType.Minimum) && (type != HeapType.Maximum)) { throw new ArgumentOutOfRangeException("type"); } thisType = type; data = new List(capacity) {default(T)}; comparerToUse = type == HeapType.Minimum ? comparer : new ReverseComparer(comparer); } #endregion #region Public Members /// /// /// /// /// public T Root { get { #region Validation if (Count == 0) { throw new InvalidOperationException(heapIsEmpty); } #endregion return data[1]; } } /// /// /// /// /// public T RemoveRoot() { #region Validation if (Count == 0) { throw new InvalidOperationException(heapIsEmpty); } #endregion // The minimum item to return. var minimum = data[1]; RemoveRootItem(minimum); return minimum; } /// /// Removes the root item. /// /// The item. /// /// Notes to Inheritors: /// Derived classes can override this method to change the behavior of the method. /// protected virtual void RemoveRootItem(T item) { // The last item in the heap var last = data[Count]; data.RemoveAt(Count); // If there's still items left in this heap, re-heapify it. if (Count > 0) { // Re-heapify the binary tree to conform to the heap property var counter = 1; while ((counter * 2) < (data.Count)) { var child = counter * 2; if (((child + 1) < (data.Count)) && (comparerToUse.Compare(data[child + 1], data[child]) < 0)) { child++; } if (comparerToUse.Compare(last, data[child]) <= 0) { break; } data[counter] = data[child]; counter = child; } data[counter] = last; } } /// /// Gets the type of heap represented by this instance. /// /// The type of heap. /// /// /// /// [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")] public HeapType Type { get { return thisType; } } #endregion #region ICollection Members /// /// /// /// /// public bool IsEmpty { get { return Count == 0; } } /// /// /// /// /// public bool Contains(T item) { return data.Contains(item); } /// /// /// /// /// public void CopyTo(T[] array, int arrayIndex) { #region Validation Guard.ArgumentNotNull(array, "array"); if ((array.Length - arrayIndex) < Count) { throw new ArgumentException(Constants.NotEnoughSpaceInTheTargetArray, "array"); } #endregion for (var i = 1; i < data.Count; i++) { array[arrayIndex++] = data[i]; } } /// /// /// /// /// public int Count { get { return data.Count - 1; } } /// /// /// /// /// public void Add(T item) { AddItem(item); } /// /// Adds the item. /// /// The item to add. /// /// Notes to Inheritors: /// Derived classes can override this method to change the behavior of the method. /// protected virtual void AddItem(T item) { // Add a dummy to the end of the list (it will be replaced) data.Add(default(T)); var counter = data.Count - 1; while ((counter > 1) && (comparerToUse.Compare(data[counter / 2], item) > 0)) { data[counter] = data[counter / 2]; counter = counter / 2; } data[counter] = item; } /// /// Always. [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")] bool ICollection.Remove(T item) { throw new NotSupportedException(); } /// /// Returns an enumerator that iterates through the collection. /// /// /// A that can be used to iterate through the collection. /// /// /// /// /// public IEnumerator GetEnumerator() { for (var i = 1; i < data.Count; i++) { yield return data[i]; } } /// /// /// /// /// public void Clear() { ClearItems(); } /// /// Clears all the objects in this instance. /// /// /// Notes to Inheritors: /// Derived classes can override this method to change the behavior of the method. /// protected virtual void ClearItems() { data.RemoveRange(1, data.Count - 1); // Clears all objects in this instance except the first dummy one. } #endregion #region ICollection Members /// /// /// /// /// public bool IsReadOnly { get { return false; } } #endregion #region IEnumerable Members /// IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion } }