using System.Linq; namespace System.Collections.Generic; /// /// Binary heap implementation. /// /// Provided type. [Serializable] public sealed class BinaryHeap : IEnumerable where T : IComparable { #region Fields T[] items; private int capacity; private int count; private readonly int initialCapacity; #endregion #region Properties /// /// Minimum value from the heap. /// public T Min { get { return this.items[1]; } } /// /// Maximum value from the heap. /// public T Max { get { return this.items[this.count]; } } /// /// Capacity of the heap. /// public int Capacity { get => this.capacity; set { if (value > this.capacity) { Array.Resize(ref this.items, value); this.capacity = value; } } } /// /// Number of elements in the heap. /// public int Count { get => this.count; } #endregion #region Constructors /// /// Constructor for a binary heap data structure. /// public BinaryHeap() { this.capacity = 10; this.initialCapacity = this.capacity; this.items = new T[this.capacity]; } /// /// Constructor for a binary heap data structure. /// /// Initial capacity of the heap. Used for initial alocation of the array. public BinaryHeap(int capacity) { this.capacity = capacity; this.initialCapacity = capacity; this.items = new T[capacity]; } #endregion #region Public Methods /// /// Adds value to the queue. /// /// Value to be added. public void Add(T value) { if (this.count == this.Capacity - 1) { this.Capacity = 2 * this.Capacity; } var position = ++this.count; for (; position > 1 && value.CompareTo(this.items[position / 2]) < 0; position /= 2) { this.items[position] = this.items[position / 2]; } this.items[position] = value; } /// /// Removes the item at the root. Throws exception if there are no items in the heap. /// /// Value removed. public T Remove() { if (this.count == 0) { throw new IndexOutOfRangeException("Heap is empty!"); } var min = this.items[1]; this.items[1] = this.items[this.count--]; this.BubbleDown(1); return min; } /// /// Peeks at the item at the root. Throws exception if there are no items in the heap. /// /// public T Peek() { if (this.count == 0) { throw new IndexOutOfRangeException("Heap is empty!"); } var min = this.items[1]; return min; } /// /// Return the heap structure as an array /// /// Array with values sorted as in heap public T[] ToArray() { var newArray = new T[this.count]; Array.Copy(this.items, 1, newArray, 0, this.count); return newArray; } /// /// Determines whether the heap contains specified value /// /// Value to locate in the heap /// public bool Contains(T value) { return this.items.Contains(value); } /// /// Clears the heap /// public void Clear() { this.count = 0; } /// /// Clears the heap. /// /// Specifies if the underlying array should be cleared as well public void Clear(bool completeClear) { this.count = 0; if (completeClear) { this.capacity = this.initialCapacity; this.items = new T[this.initialCapacity]; } } /// /// Returns an enumerator that iterates over the heap. /// /// Enumerator that iterates over the heap. public IEnumerator GetEnumerator() { for (var i = 0; i < this.count; i++) { yield return this.items[i + 1]; } } #endregion #region Private Methods /// /// Bubble the specified element to its position /// /// Index of element to bubble private void BubbleDown(int index) { var temp = this.items[index]; int childIndex; for (; 2 * index <= this.count; index = childIndex) { childIndex = 2 * index; if (childIndex != this.Count && this.items[childIndex].CompareTo(this.items[childIndex + 1]) > 0) { childIndex++; } if (temp.CompareTo(this.items[childIndex]) > 0) { this.items[index] = this.items[childIndex]; } else { break; } } this.items[index] = temp; } /// /// Implementation of IEnumerator. /// /// Enumerator over the array. IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } #endregion }