using System;
using System.Collections.Generic;
using System.Text;
namespace Framework.Collections
{
///
/// The IndexMinPriorityQueue class represents an indexed priority queue of generic keys.
///
/// IndexMinPQ class from Princeton University's Java Algorithms
/// Type must implement IComparable interface
public class IndexMinPriorityQueue where T : IComparable
{
private readonly T[] _keys;
private readonly int _maxSize;
private readonly int[] _pq;
private readonly int[] _qp;
///
/// Constructs an empty indexed priority queue with indices between 0 and the specified maxSize - 1
///
/// The maximum size of the indexed priority queue
public IndexMinPriorityQueue(int maxSize)
{
_maxSize = maxSize;
Size = 0;
_keys = new T[_maxSize + 1];
_pq = new int[_maxSize + 1];
_qp = new int[_maxSize + 1];
for (int i = 0; i < _maxSize; i++)
{
_qp[i] = -1;
}
}
///
/// The number of keys on this indexed priority queue
///
public int Size { get; private set; }
///
/// Is the indexed priority queue empty?
///
/// True if the indexed priority queue is empty, false otherwise
public bool IsEmpty()
{
return Size == 0;
}
///
/// Is the specified parameter i an index on the priority queue?
///
/// An index to check for on the priority queue
/// True if the specified parameter i is an index on the priority queue, false otherwise
public bool Contains(int i)
{
return _qp[i] != -1;
}
///
/// Associates the specified key with the specified index
///
/// The index to associate the key with
/// The key to associate with the index
public void Insert(int index, T key)
{
Size++;
_qp[index] = Size;
_pq[Size] = index;
_keys[index] = key;
Swim(Size);
}
///
/// Returns an index associated with a minimum key
///
/// An index associated with a minimum key
public int MinIndex()
{
return _pq[1];
}
///
/// Returns a minimum key
///
/// A minimum key
public T MinKey()
{
return _keys[_pq[1]];
}
///
/// Removes a minimum key and returns its associated index
///
/// An index associated with a minimum key that was removed
public int DeleteMin()
{
int min = _pq[1];
Exchange(1, Size--);
Sink(1);
_qp[min] = -1;
_keys[_pq[Size + 1]] = default(T);
_pq[Size + 1] = -1;
return min;
}
///
/// Returns the key associated with the specified index
///
/// The index of the key to return
/// The key associated with the specified index
public T KeyAt(int index)
{
return _keys[index];
}
///
/// Change the key associated with the specified index to the specified value
///
/// The index of the key to change
/// Change the key associated with the specified index to this key
public void ChangeKey(int index, T key)
{
_keys[index] = key;
Swim(_qp[index]);
Sink(_qp[index]);
}
///
/// Decrease the key associated with the specified index to the specified value
///
/// The index of the key to decrease
/// Decrease the key associated with the specified index to this key
public void DecreaseKey(int index, T key)
{
_keys[index] = key;
Swim(_qp[index]);
}
///
/// Increase the key associated with the specified index to the specified value
///
/// The index of the key to increase
/// Increase the key associated with the specified index to this key
public void IncreaseKey(int index, T key)
{
_keys[index] = key;
Sink(_qp[index]);
}
///
/// Remove the key associated with the specified index
///
/// The index of the key to remove
public void Delete(int index)
{
int i = _qp[index];
Exchange(i, Size--);
Swim(i);
Sink(i);
_keys[index] = default(T);
_qp[index] = -1;
}
private bool Greater(int i, int j)
{
return _keys[_pq[i]].CompareTo(_keys[_pq[j]]) > 0;
}
private void Exchange(int i, int j)
{
int swap = _pq[i];
_pq[i] = _pq[j];
_pq[j] = swap;
_qp[_pq[i]] = i;
_qp[_pq[j]] = j;
}
private void Swim(int k)
{
while (k > 1 && Greater(k / 2, k))
{
Exchange(k, k / 2);
k = k / 2;
}
}
private void Sink(int k)
{
while (2 * k <= Size)
{
int j = 2 * k;
if (j < Size && Greater(j, j + 1))
{
j++;
}
if (!Greater(k, j))
{
break;
}
Exchange(k, j);
k = j;
}
}
}
}