using System;
using System.Collections;
namespace Holo.Virtual.Rooms.Pathfinding
{
///
/// The Heap allows to maintain a list sorted as long as needed.
/// If no IComparer interface has been provided at construction, then the list expects the Objects to implement IComparer.
/// If the list is not sorted it behaves like an ordinary list.
/// When sorted, the list's "Add" method will put new objects at the right place.
/// As well the "Contains" and "IndexOf" methods will perform a binary search.
///
public class Heap : IList, ICloneable
{
#region Private Members
private ArrayList FList;
private IComparer FComparer = null;
private bool FUseObjectsComparison;
#endregion
#region Constructors
///
/// Default constructor.
/// Since no IComparer is provided here, added objects must implement the IComparer interface.
///
public Heap()
{
InitProperties(null, 0);
}
///
/// Constructor.
/// Since no IComparer is provided, added objects must implement the IComparer interface.
///
/// Capacity of the list (ArrayList.Capacity)
public Heap(int Capacity)
{
InitProperties(null, Capacity);
}
///
/// Constructor.
///
/// Will be used to compare added elements for sort and search operations.
public Heap(IComparer Comparer)
{
InitProperties(Comparer, 0);
}
///
/// Constructor.
///
/// Will be used to compare added elements for sort and search operations.
/// Capacity of the list (ArrayList.Capacity)
public Heap(IComparer Comparer, int Capacity)
{
InitProperties(Comparer, Capacity);
}
#endregion
#region Properties
///
/// If set to true, it will not be possible to add an object to the list if its value is already in the list.
///
public bool AddDuplicates
{
set
{
FAddDuplicates = value;
}
get
{
return FAddDuplicates;
}
}
private bool FAddDuplicates;
///
/// Idem ArrayList
///
public int Capacity
{
get
{
return FList.Capacity;
}
set
{
FList.Capacity = value;
}
}
#endregion
#region IList Members
///
/// IList implementation.
/// Gets object's value at a specified index.
/// The set operation is impossible on a Heap.
///
/// Index is less than zero or Index is greater than Count.
/// [] operator cannot be used to set a value on a Heap.
public object this[int Index]
{
get
{
if (Index >= FList.Count || Index < 0)
throw new ArgumentOutOfRangeException("Index is less than zero or Index is greater than Count.");
return FList[Index];
}
set
{
throw new InvalidOperationException("[] operator cannot be used to set a value in a Heap.");
}
}
///
/// IList implementation.
/// Adds the object at the right place.
///
/// The object to add.
/// The index where the object has been added.
/// The Heap is set to use object's IComparable interface, and the specifed object does not implement this interface.
public int Add(object O)
{
int Return = -1;
if (ObjectIsCompliant(O))
{
int Index = IndexOf(O);
int NewIndex = Index >= 0 ? Index : -Index - 1;
if (NewIndex >= Count) FList.Add(O);
else FList.Insert(NewIndex, O);
Return = NewIndex;
}
return Return;
}
///
/// IList implementation.
/// Search for a specified object in the list.
/// If the list is sorted, a BinarySearch is performed using IComparer interface.
/// Else the Object.Equals implementation is used.
///
/// The object to look for
/// true if the object is in the list, otherwise false.
public bool Contains(object O)
{
return FList.BinarySearch(O, FComparer) >= 0;
}
///
/// IList implementation.
/// Returns the index of the specified object in the list.
/// If the list is sorted, a BinarySearch is performed using IComparer interface.
/// Else the Object.Equals implementation of objects is used.
///
/// The object to locate.
///
/// If the object has been found, a positive integer corresponding to its position.
/// If the objects has not been found, a negative integer which is the bitwise complement of the index of the next element.
///
public int IndexOf(object O)
{
int Result = -1;
Result = FList.BinarySearch(O, FComparer);
while (Result > 0 && FList[Result - 1].Equals(O))
Result--;
return Result;
}
///
/// IList implementation.
/// Idem ArrayList
///
public bool IsFixedSize
{
get
{
return FList.IsFixedSize;
}
}
///
/// IList implementation.
/// Idem ArrayList
///
public bool IsReadOnly
{
get
{
return FList.IsReadOnly;
}
}
///
/// IList implementation.
/// Idem ArrayList
///
public void Clear()
{
FList.Clear();
}
///
/// IList implementation.
/// Cannot be used on a Heap.
///
/// The index before which the object must be added.
/// The object to add.
/// Insert method cannot be called on a Heap.
public void Insert(int Index, object O)
{
throw new InvalidOperationException("Insert method cannot be called on a Heap.");
}
///
/// IList implementation.
/// Idem ArrayList
///
/// The object whose value must be removed if found in the list.
public void Remove(object Value)
{
FList.Remove(Value);
}
///
/// IList implementation.
/// Idem ArrayList
///
/// Index of object to remove.
public void RemoveAt(int Index)
{
FList.RemoveAt(Index);
}
#endregion
#region IList.ICollection Members
///
/// IList.ICollection implementation.
/// Idem ArrayList
///
///
///
public void CopyTo(Array array, int arrayIndex) { FList.CopyTo(array, arrayIndex); }
///
/// IList.ICollection implementation.
/// Idem ArrayList
///
public int Count { get { return FList.Count; } }
///
/// IList.ICollection implementation.
/// Idem ArrayList
///
public bool IsSynchronized { get { return FList.IsSynchronized; } }
///
/// IList.ICollection implementation.
/// Idem ArrayList
///
public object SyncRoot { get { return FList.SyncRoot; } }
#endregion
#region IList.IEnumerable Members
///
/// IList.IEnumerable implementation.
/// Idem ArrayList
///
/// Enumerator on the list.
public IEnumerator GetEnumerator()
{
return FList.GetEnumerator();
}
#endregion
#region IClonable Members
///
/// ICloneable implementation.
/// Idem ArrayList
///
/// Cloned object.
public object Clone()
{
Heap Clone = new Heap(FComparer, FList.Capacity);
Clone.FList = (ArrayList)FList.Clone();
Clone.FAddDuplicates = FAddDuplicates;
return Clone;
}
#endregion
#region Delegate Members
///
/// Defines an equality for two objects
///
public delegate bool Equality(object Object1, object Object2);
#endregion
#region Overridden Members
///
/// Object.ToString() override.
/// Build a string to represent the list.
///
/// The string refecting the list.
public override string ToString()
{
string OutString = "{";
for (int i = 0; i < FList.Count; i++)
OutString += FList[i].ToString() + (i != FList.Count - 1 ? "; " : "}");
return OutString;
}
///
/// Object.Equals() override.
///
/// true if object is equal to this, otherwise false.
public override bool Equals(object Object)
{
Heap SL = (Heap)Object;
if (SL.Count != Count)
return false;
for (int i = 0; i < Count; i++)
if (!SL[i].Equals(this[i]))
return false;
return true;
}
///
/// Object.GetHashCode() override.
///
/// Hash code for this.
public override int GetHashCode()
{
return FList.GetHashCode();
}
#endregion
#region Public Members
///
/// Idem IndexOf(object), but starting at a specified position in the list
///
/// The object to locate.
/// The index for start position.
///
public int IndexOf(object Object, int Start)
{
int Result = -1;
Result = FList.BinarySearch(Start, FList.Count - Start, Object, FComparer);
while (Result > Start && FList[Result - 1].Equals(Object))
Result--;
return Result;
}
///
/// Idem IndexOf(object), but with a specified equality function
///
/// The object to locate.
/// Equality function to use for the search.
///
public int IndexOf(object Object, Equality AreEqual)
{
for (int i = 0; i < FList.Count; i++)
if (AreEqual(FList[i], Object)) return i;
return -1;
}
///
/// Idem IndexOf(object), but with a start index and a specified equality function
///
/// The object to locate.
/// The index for start position.
/// Equality function to use for the search.
///
public int IndexOf(object Object, int Start, Equality AreEqual)
{
if (Start < 0 || Start >= FList.Count) throw new ArgumentException("Start index must belong to [0; Count-1].");
for (int i = Start; i < FList.Count; i++)
if (AreEqual(FList[i], Object)) return i;
return -1;
}
///
/// The objects will be added at the right place.
///
/// The object to add.
/// The index where the object has been added.
/// The Heap is set to use object's IComparable interface, and the specifed object does not implement this interface.
public void AddRange(ICollection C)
{
foreach (object Object in C)
Add(Object);
}
///
/// Cannot be called on a Heap.
///
/// The index before which the objects must be added.
/// The object to add.
/// Insert cannot be called on a Heap.
public void InsertRange(int Index, ICollection C)
{
throw new InvalidOperationException("Insert cannot be called on a Heap.");
}
///
/// Limits the number of occurrences of a specified value.
/// Same values are equals according to the Equals() method of objects in the list.
/// The first occurrences encountered are kept.
///
/// Value whose occurrences number must be limited.
/// Number of occurrences to keep
public void LimitOccurrences(object Value, int NumberToKeep)
{
if (Value == null)
throw new ArgumentNullException("Value");
int Pos = 0;
while ((Pos = IndexOf(Value, Pos)) >= 0)
{
if (NumberToKeep <= 0)
FList.RemoveAt(Pos);
else
{
Pos++;
NumberToKeep--;
}
if (FComparer.Compare(FList[Pos], Value) > 0)
break;
}
}
///
/// Removes all duplicates in the list.
/// Each value encountered will have only one representant.
///
public void RemoveDuplicates()
{
int PosIt;
PosIt = 0;
while (PosIt < Count - 1)
{
if (FComparer.Compare(this[PosIt], this[PosIt + 1]) == 0)
RemoveAt(PosIt);
else
PosIt++;
}
}
///
/// Returns the object of the list whose value is minimum
///
/// The minimum object in the list
public int IndexOfMin()
{
int RetInt = -1;
if (FList.Count > 0)
{
RetInt = 0;
object RetObj = FList[0];
}
return RetInt;
}
///
/// Returns the object of the list whose value is maximum
///
/// The maximum object in the list
public int IndexOfMax()
{
int RetInt = -1;
if (FList.Count > 0)
{
RetInt = FList.Count - 1;
object RetObj = FList[FList.Count - 1];
}
return RetInt;
}
///
/// Returns the topmost object on the list and removes it from the list
///
/// Returns the topmost object on the list
public object Pop()
{
if (FList.Count == 0)
throw new InvalidOperationException("The heap is empty.");
object Object = FList[Count - 1];
FList.RemoveAt(Count - 1);
return (Object);
}
///
/// Pushes an object on list. It will be inserted at the right spot.
///
/// Object to add to the list
///
public int Push(object Object)
{
return (Add(Object));
}
#endregion
#region Private Members
private bool ObjectIsCompliant(object Object)
{
if (FUseObjectsComparison && !(Object is IComparable))
throw new ArgumentException("The Heap is set to use the IComparable interface of objects, and the object to add does not implement the IComparable interface.");
if (!FAddDuplicates && Contains(Object))
return false;
return true;
}
private class Comparison : IComparer
{
public int Compare(object Object1, object Object2)
{
IComparable C = Object1 as IComparable;
return C.CompareTo(Object2);
}
}
private void InitProperties(IComparer Comparer, int Capacity)
{
if (Comparer != null)
{
FComparer = Comparer;
FUseObjectsComparison = false;
}
else
{
FComparer = new Comparison();
FUseObjectsComparison = true;
}
FList = Capacity > 0 ? new ArrayList(Capacity) : new ArrayList();
FAddDuplicates = true;
}
#endregion
}
}