using System;
using System.Collections.Generic;
namespace DarkWood
{
///
/// 支持快速查找(Contains)和动态更新优先级(UpdatePriority)的优先队列。
/// 默认实现为最小堆(Min-Heap)。
///
/// 元素类型(必须是唯一的,且非空)
/// 优先级类型
public sealed class PriorityQueue where TElement : notnull
{
private readonly List<(TElement Element, TPriority Priority)> _heap;
private readonly Dictionary _indices;
private readonly IComparer _comparer;
public int Count => _heap.Count;
public bool IsEmpty => _heap.Count == 0;
///
/// 初始化 PriorityQueue 的新实例。
///
public PriorityQueue() : this(Comparer.Default) { }
public PriorityQueue(IComparer comparer)
{
_heap = new List<(TElement, TPriority)>();
_indices = new Dictionary();
_comparer = comparer ?? Comparer.Default;
}
///
/// 将元素入队。时间复杂度: O(log N)
///
public void Enqueue(TElement element, TPriority priority)
{
if (_indices.ContainsKey(element))
{
throw new InvalidOperationException("元素已存在于队列中,请使用 UpdatePriority 更新。");
}
_heap.Add((element, priority));
int index = _heap.Count - 1;
_indices[element] = index;
SiftUp(index);
}
///
/// 移除并返回具有最小优先级值的元素。时间复杂度: O(log N)
///
public TElement Dequeue()
{
if (_heap.Count == 0) throw new InvalidOperationException("队列为空。");
var result = _heap[0].Element;
RemoveAt(0);
return result;
}
///
/// 返回具有最小优先级值的元素但不移除。时间复杂度: O(1)
///
public TElement Peek()
{
if (_heap.Count == 0) throw new InvalidOperationException("队列为空。");
return _heap[0].Element;
}
///
/// 检查元素是否存在于队列中。时间复杂度: O(1)
///
public bool Contains(TElement element)
{
return _indices.ContainsKey(element);
}
///
/// 更新已存在元素的优先级。时间复杂度: O(log N)
///
public void UpdatePriority(TElement element, TPriority newPriority)
{
if (!_indices.TryGetValue(element, out int index))
{
throw new KeyNotFoundException("该元素不存在于队列中。");
}
TPriority oldPriority = _heap[index].Priority;
_heap[index] = (element, newPriority);
int comparison = _comparer.Compare(newPriority, oldPriority);
if (comparison < 0)
{
// 新优先级更小(更高),需要上浮
SiftUp(index);
}
else if (comparison > 0)
{
// 新优先级更大(更低),需要下沉
SiftDown(index);
}
}
///
/// 尝试获取元素的当前优先级。
///
public bool TryGetPriority(TElement element, out TPriority priority)
{
if (_indices.TryGetValue(element, out int index))
{
priority = _heap[index].Priority;
return true;
}
priority = default!;
return false;
}
// --- 私有辅助方法 ---
private void RemoveAt(int index)
{
int lastIndex = _heap.Count - 1;
var itemToRemove = _heap[index];
// 交换当前节点与最后一个节点
Swap(index, lastIndex);
// 移除最后一个节点(即原来的目标节点)
_heap.RemoveAt(lastIndex);
_indices.Remove(itemToRemove.Element);
if (index < lastIndex) // 如果移除的不是最后一个元素
{
// 需要重新平衡堆
SiftDown(index);
SiftUp(index);
}
}
private void SiftUp(int index)
{
while (index > 0)
{
int parentIndex = (index - 1) / 2;
if (_comparer.Compare(_heap[index].Priority, _heap[parentIndex].Priority) >= 0)
{
break;
}
Swap(index, parentIndex);
index = parentIndex;
}
}
private void SiftDown(int index)
{
int lastIndex = _heap.Count - 1;
while (true)
{
int leftChild = 2 * index + 1;
int rightChild = 2 * index + 2;
int smallest = index;
if (leftChild <= lastIndex &&
_comparer.Compare(_heap[leftChild].Priority, _heap[smallest].Priority) < 0)
{
smallest = leftChild;
}
if (rightChild <= lastIndex &&
_comparer.Compare(_heap[rightChild].Priority, _heap[smallest].Priority) < 0)
{
smallest = rightChild;
}
if (smallest == index) break;
Swap(index, smallest);
index = smallest;
}
}
private void Swap(int i, int j)
{
(_heap[j], _heap[i]) = (_heap[i], _heap[j]);
// 关键:同时更新索引字典
_indices[_heap[i].Element] = i;
_indices[_heap[j].Element] = j;
}
}
}