using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace CarFire
{
///
/// Why .NET doesn't already provide such a basic data structure
/// as a priority queue is anybody's best guess. This is an interface
/// for a queue class which treats the items themselves as keys,
/// the relative priorities being determined by a comparison between
/// them.
///
/// The type of item to queue. This must be a
/// comparable class.
public interface IPriorityQueue where T : IComparable
{
///
/// Add a new item to the priority queue.
///
/// The item to add.
void Add(T item);
///
/// Get the item with the highest priority, removing it
/// from the priority queue.
///
/// The highest priority item.
T GetNext();
///
/// Get the item with the highest priority, but keep it in
/// the priority queue.
///
/// The highest priority item.
T Peek();
///
/// Notify the priority queue that the priority of a certain item
/// has improved. If the items is not in the queue, it is added.
/// Do not use this to demote items. The internal structures will
/// be reconfigured in order to ensure correct priority queueing.
///
/// The item that improved.
void Promote(T item);
///
/// Remove all the items from the priority queue.
///
void Clear();
///
/// Get the number of items in the priority queue.
///
int Count { get; }
}
///
/// A minimum binary heap implementing a priority queue.
///
/// The type of items to load in the heap.
public class BinaryHeap : IPriorityQueue where T : IComparable
{
#region Public Properties
///
/// Get the number of items in the binary heap.
///
public int Count { get { return mSize; } }
#endregion
#region Public Methods
///
/// Construct a binary heap.
///
public BinaryHeap()
{
mList.Add(default(T));
}
///
/// Construct a binary heap with a predetermined capacity.
/// The heap is dynamically-sized, but it will be more
/// efficient if you set the capacity to the number of items
/// you plan to add.
///
/// The capacity of the heap.
public BinaryHeap(int capacity)
{
mList.Capacity = capacity;
mList.Add(default(T));
}
///
/// Add a new item to the heap.
///
/// The item to add.
public void Add(T item)
{
mList.Add(item);
mSize++;
PercolateUp(mSize);
}
///
/// Get the item with the lowest value, removing it from the heap.
///
/// The highest priority item.
public T GetNext()
{
Debug.Assert(mSize > 0);
T next = mList[1];
mList[1] = mList[mSize];
PercolateDown(1);
mList.RemoveAt(mSize);
mSize--;
return next;
}
///
/// Get the item with the lowest value, but keep it in the heap.
///
/// The highest priority item.
public T Peek()
{
Debug.Assert(mSize > 0);
return mList[1];
}
///
/// Decrease the value of one of the items in the heap. If the
/// item is not already in the heap, it is added.
///
/// The item to change.
public void Promote(T item)
{
for (int i = 1; i < mList.Count; i++)
{
if (item.Equals(mList[i]))
{
mList[i] = item;
if (PercolateUp(i) == i) PercolateDown(i);
return;
}
}
Add(item);
}
///
/// Remove all the items from the heap.
///
public void Clear()
{
mList.Clear();
mSize = 0;
}
#endregion
#region Private Methods
int PercolateUp(int index)
{
T temp = mList[index];
for (int parent; index > 1; index = parent)
{
parent = index / 2;
if (temp.CompareTo(mList[parent]) < 0) mList[index] = mList[parent];
else break;
}
mList[index] = temp;
return index;
}
int PercolateDown(int index)
{
T temp = mList[index];
for (int child; index * 2 <= mSize; index = child)
{
child = index * 2;
if (child != mSize && mList[child].CompareTo(mList[child + 1]) > 0) child++;
if (temp.CompareTo(mList[child]) > 0) mList[index] = mList[child];
else break;
}
mList[index] = temp;
return index;
}
#endregion
#region Private Variables
List mList = new List();
int mSize = 0;
#endregion
}
///
/// The binary heap might be too slow for shortest path algorithms,
/// so here is a fibonacci heap which should perform better.
///
/// The type of items to load in the heap.
public class FibonacciHeap : IPriorityQueue where T : IComparable
{
#region Public Properties
///
/// Get the number of items in the fibonacci heap.
///
public int Count { get { return mCount; } }
#endregion
#region Public Methods
///
/// Construct an empty fibonacci heap.
///
public FibonacciHeap()
{
mList = new LinkedList();
mLookup = new Dictionary>();
}
///
/// Add a new item to the heap.
///
/// The item to add.
public void Add(T item)
{
LinkedListNode node = mList.AddLast(new NodeInfo(item));
if (mMin == null || item.CompareTo(mMin.Value.Item) < 0) mMin = node;
mLookup[item] = node;
mCount++;
}
///
/// Get the item with the lowest value, removing it from the heap.
///
/// The highest priority item.
public T GetNext()
{
LinkedListNode temp = mMin;
mList.Remove(mMin);
mMin = null;
LinkedListNode node = temp.Value.Children.First;
while (node != null)
{
Cut(node);
node = temp.Value.Children.First;
}
Consolidate();
mLookup.Remove(temp.Value.Item);
mCount--;
return temp.Value.Item;
}
///
/// Get the item with the lowest value, but keep it in the heap.
///
/// The highest priority item.
public T Peek()
{
return mMin.Value.Item;
}
///
/// Decrease the value of one of the items in the heap. If the
/// item is not already in the heap, it is added.
///
/// The item to change.
public void Promote(T item)
{
LinkedListNode node;
if (mLookup.TryGetValue(item, out node))
{
LinkedListNode parent = node.Value.Parent;
if (parent != null)
{
if (node.Value.Item.CompareTo(parent.Value.Item) < 0)
{
Cut(node);
CascadingCut(parent);
if (node.Value.Item.CompareTo(mMin.Value.Item) < 0) mMin = node;
}
}
else if (node.Value.Item.CompareTo(mMin.Value.Item) < 0) mMin = node;
}
else
{
Add(item);
}
}
///
/// Remove all the items from the heap.
///
public void Clear()
{
mList.Clear();
mMin = null;
mCount = 0;
mLookup.Clear();
}
#endregion
#region Private Methods
// Builds up the binomial trees. More importantly, it sets the min
// pointeer and ensures that no root binomial tree has the same degree.
void Consolidate()
{
LinkedListNode[] degree = new LinkedListNode[64];
for (LinkedListNode node = mList.First; node != null;)
{
LinkedListNode match = degree[node.Value.Degree];
if (match == null)
{
if (mMin == null || node.Value.Item.CompareTo(mMin.Value.Item) <= 0) mMin = node;
degree[node.Value.Degree] = node;
node = node.Next;
}
else
{
degree[node.Value.Degree] = null;
if (node.Value.Item.CompareTo(match.Value.Item) < 0)
{
Link(match, node);
}
else
{
mList.Remove(match);
mList.AddAfter(node, match);
Link(node, match);
node = match;
}
}
}
}
// Removes child from whatever list it is in and makes it a child
// of parent. This is for building up the binomial trees.
void Link(LinkedListNode child, LinkedListNode parent)
{
child.List.Remove(child);
parent.Value.Children.AddLast(child);
child.Value.Parent = parent;
child.Value.IsMarked = false;
}
// Removes node from whatever list it is in and makes it a root binomial
// tree.
void Cut(LinkedListNode node)
{
node.List.Remove(node);
mList.AddLast(node);
node.Value.Parent = null;
node.Value.IsMarked = false;
}
// Cuts each node that is marked, following the ancestry until it finds
// an unmarked ancestor (in which case it marks it) or a root node.
void CascadingCut(LinkedListNode node)
{
while (node.Value.Parent != null)
{
if (node.Value.IsMarked)
{
Cut(node);
node = node.Value.Parent;
}
else
{
node.Value.IsMarked = true;
break;
}
}
}
#endregion
#region Private Types
// This container class has the information we need to form
// a tree out of linked lists.
class NodeInfo
{
public LinkedListNode Parent;
public LinkedList Children = new LinkedList();
public bool IsMarked = false;
public int Degree { get { return Children.Count; } }
public T Item { get { return mItem; } }
public NodeInfo(T item)
{
mItem = item;
}
T mItem;
}
#endregion
#region Private Variables
LinkedList mList;
LinkedListNode mMin;
int mCount;
// To speed up promotions, we need a fast lookup for nodes.
Dictionary> mLookup;
#endregion
}
}