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
}