using System;
using System.Collections;
namespace BenTools.Data
{
public interface IPriorityQueue : ICollection, ICloneable, IList
{
int Push(object O);
object Pop();
object Peek();
void Update(int i);
}
public class BinaryPriorityQueue : IPriorityQueue, ICollection, ICloneable, IList
{
protected ArrayList InnerList = new ArrayList();
protected IComparer Comparer;
#region contructors
public BinaryPriorityQueue() : this(System.Collections.Comparer.Default)
{}
public BinaryPriorityQueue(IComparer c)
{
Comparer = c;
}
public BinaryPriorityQueue(int C) : this(System.Collections.Comparer.Default,C)
{}
public BinaryPriorityQueue(IComparer c, int Capacity)
{
Comparer = c;
InnerList.Capacity = Capacity;
}
protected BinaryPriorityQueue(ArrayList Core, IComparer Comp, bool Copy)
{
if(Copy)
InnerList = Core.Clone() as ArrayList;
else
InnerList = Core;
Comparer = Comp;
}
#endregion
protected void SwitchElements(int i, int j)
{
object h = InnerList[i];
InnerList[i] = InnerList[j];
InnerList[j] = h;
}
protected virtual int OnCompare(int i, int j)
{
return Comparer.Compare(InnerList[i],InnerList[j]);
}
#region public methods
///
/// Push an object onto the PQ
///
/// The new object
/// The index in the list where the object is _now_. This will change when objects are taken from or put onto the PQ.
public int Push(object O)
{
int p = InnerList.Count,p2;
InnerList.Add(O); // E[p] = O
do
{
if(p==0)
break;
p2 = (p-1)/2;
if(OnCompare(p,p2)<0)
{
SwitchElements(p,p2);
p = p2;
}
else
break;
}while(true);
return p;
}
///
/// Get the smallest object and remove it.
///
/// The smallest object
public object Pop()
{
object result = InnerList[0];
int p = 0,p1,p2,pn;
InnerList[0] = InnerList[InnerList.Count-1];
InnerList.RemoveAt(InnerList.Count-1);
do
{
pn = p;
p1 = 2*p+1;
p2 = 2*p+2;
if(InnerList.Count>p1 && OnCompare(p,p1)>0) // links kleiner
p = p1;
if(InnerList.Count>p2 && OnCompare(p,p2)>0) // rechts noch kleiner
p = p2;
if(p==pn)
break;
SwitchElements(p,pn);
}while(true);
return result;
}
///
/// Notify the PQ that the object at position i has changed
/// and the PQ needs to restore order.
/// Since you dont have access to any indexes (except by using the
/// explicit IList.this) you should not call this function without knowing exactly
/// what you do.
///
/// The index of the changed object.
public void Update(int i)
{
int p = i,pn;
int p1,p2;
do // aufsteigen
{
if(p==0)
break;
p2 = (p-1)/2;
if(OnCompare(p,p2)<0)
{
SwitchElements(p,p2);
p = p2;
}
else
break;
}while(true);
if(pp1 && OnCompare(p,p1)>0) // links kleiner
p = p1;
if(InnerList.Count>p2 && OnCompare(p,p2)>0) // rechts noch kleiner
p = p2;
if(p==pn)
break;
SwitchElements(p,pn);
}while(true);
}
///
/// Get the smallest object without removing it.
///
/// The smallest object
public object Peek()
{
if(InnerList.Count>0)
return InnerList[0];
return null;
}
public bool Contains(object value)
{
return InnerList.Contains(value);
}
public void Clear()
{
InnerList.Clear();
}
public int Count
{
get
{
return InnerList.Count;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return InnerList.GetEnumerator();
}
public void CopyTo(Array array, int index)
{
InnerList.CopyTo(array,index);
}
public object Clone()
{
return new BinaryPriorityQueue(InnerList,Comparer,true);
}
public bool IsSynchronized
{
get
{
return InnerList.IsSynchronized;
}
}
public object SyncRoot
{
get
{
return this;
}
}
#endregion
#region explicit implementation
bool IList.IsReadOnly
{
get
{
return false;
}
}
object IList.this[int index]
{
get
{
return InnerList[index];
}
set
{
InnerList[index] = value;
Update(index);
}
}
int IList.Add(object o)
{
return Push(o);
}
void IList.RemoveAt(int index)
{
throw new NotSupportedException();
}
void IList.Insert(int index, object value)
{
throw new NotSupportedException();
}
void IList.Remove(object value)
{
throw new NotSupportedException();
}
int IList.IndexOf(object value)
{
throw new NotSupportedException();
}
bool IList.IsFixedSize
{
get
{
return false;
}
}
public static BinaryPriorityQueue Syncronized(BinaryPriorityQueue P)
{
return new BinaryPriorityQueue(ArrayList.Synchronized(P.InnerList),P.Comparer,false);
}
public static BinaryPriorityQueue ReadOnly(BinaryPriorityQueue P)
{
return new BinaryPriorityQueue(ArrayList.ReadOnly(P.InnerList),P.Comparer,false);
}
#endregion
}
}