Files
OpenRA/OpenRA.Game/Primitives/PriorityQueue.cs
2016-03-03 22:31:45 +00:00

121 lines
2.6 KiB
C#

#region Copyright & License Information
/*
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
namespace OpenRA.Primitives
{
public interface IPriorityQueue<T>
{
void Add(T item);
bool Empty { get; }
T Peek();
T Pop();
}
public class PriorityQueue<T> : IPriorityQueue<T>
{
readonly List<T[]> items;
readonly IComparer<T> comparer;
int level, index;
public PriorityQueue() : this(Comparer<T>.Default)
{
}
public PriorityQueue(IComparer<T> comparer)
{
items = new List<T[]> { new T[1] };
this.comparer = comparer;
}
public void Add(T item)
{
var addLevel = level;
var addIndex = index;
while (addLevel >= 1 && comparer.Compare(Above(addLevel, addIndex), item) > 0)
{
items[addLevel][addIndex] = Above(addLevel, addIndex);
--addLevel;
addIndex >>= 1;
}
items[addLevel][addIndex] = item;
if (++index >= (1 << level))
{
index = 0;
if (items.Count <= ++level)
items.Add(new T[1 << level]);
}
}
public bool Empty { get { return level == 0; } }
T At(int level, int index) { return items[level][index]; }
T Above(int level, int index) { return items[level - 1][index >> 1]; }
T Last()
{
var lastLevel = level;
var lastIndex = index;
if (--lastIndex < 0)
lastIndex = (1 << --lastLevel) - 1;
return At(lastLevel, lastIndex);
}
public T Peek()
{
if (level <= 0 && index <= 0)
throw new InvalidOperationException("PriorityQueue empty.");
return At(0, 0);
}
public T Pop()
{
var ret = Peek();
BubbleInto(0, 0, Last());
if (--index < 0)
index = (1 << --level) - 1;
return ret;
}
void BubbleInto(int intoLevel, int intoIndex, T val)
{
var downLevel = intoLevel + 1;
var downIndex = intoIndex << 1;
if (downLevel > level || (downLevel == level && downIndex >= index))
{
items[intoLevel][intoIndex] = val;
return;
}
if (downLevel <= level && downIndex < index - 1 &&
comparer.Compare(At(downLevel, downIndex), At(downLevel, downIndex + 1)) >= 0)
++downIndex;
if (comparer.Compare(val, At(downLevel, downIndex)) <= 0)
{
items[intoLevel][intoIndex] = val;
return;
}
items[intoLevel][intoIndex] = At(downLevel, downIndex);
BubbleInto(downLevel, downIndex, val);
}
}
}