/*
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
}
}