using System; using System.Collections; using System.Collections.Generic; namespace IFramework.Queue { /// /// 快速优先级队列 /// /// 节点元素类型 public sealed class FastPriorityQueue : IFixedSizePriorityQueue where T : FastPriorityQueueNode { private int _numNodes; private T[] _nodes; /// /// Ctor /// /// 允许入队的最大数量(如果超过将导致未定义的操作) public FastPriorityQueue(int capcity) { if (capcity <= 0) throw new InvalidOperationException("New queue size cannot be smaller than 1"); _numNodes = 0; _nodes = new T[capcity + 1]; } /// /// 返回队列里的元素数量
/// O(1) ///
public int count { get { return _numNodes; } } /// /// 队列中可以入队的最大数量
/// 如果入队数量超过队列的大小(Count == MaxSize时Enqueue()),会导致未定义的操作
/// O(1) ///
public int capcity { get { return _nodes.Length - 1; } } /// /// 移除队列里的所有元素
/// O(n) (因此请勿频繁使用此方法) ///
#if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif public void Clear() { Array.Clear(_nodes, 1, _numNodes); _numNodes = 0; } /// /// 判断当前元素是否在队列中
/// 如果元素被添加到其他的队列,则结果是不确定的, /// 除非调用了之前队列的ResetNode(node)方法
/// O(1) ///
/// 需要判断的元素 /// 如果队列包含这个元素则返回true 否则为false #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif public bool Contains(T node) { #if DEBUG if (node == null) { throw new ArgumentNullException("node"); } if (node.position < 0 || node.position >= _nodes.Length) { throw new InvalidOperationException("node.position has been corrupted. Did you change it manually? Or add this node to another queue?"); } #endif return (_nodes[node.position] == node); } /// /// 将优先级节点入队,优先级值小的将会排在队列前面,优先级相同的节点任意排序
/// 如果队列是满的,则执行未定义的操作
/// 如果节点元素已经入队了,则执行未定义的操作
/// 如果节点已经加入到了其他队列,除非在此之前调用了之前队列的ResetNode(node)方法,否则结果是未定义的
/// O(log n) ///
#if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif public void Enqueue(T node, float priority) { #if DEBUG if (node == null) { throw new ArgumentNullException("node"); } if (_numNodes >= _nodes.Length - 1) { throw new InvalidOperationException($"Queue is full - node cannot be added:{node}"); } if (Contains(node)) { throw new InvalidOperationException($"Node is already enqueued:{node} "); } #endif node.priority = priority; _numNodes++; _nodes[_numNodes] = node; node.position = _numNodes; CascadeUp(node); } #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif private void CascadeUp(T node) { int parent; if (node.position > 1) { parent = node.position >> 1; T parentNode = _nodes[parent]; if (HasHigherOrEqualPriority(parentNode, node)) return; //节点更紧急, 将父节点向下移动腾出空间 _nodes[node.position] = parentNode; parentNode.position = node.position; node.position = parent; } else { return; } while (parent > 1) { parent >>= 1; T parentNode = _nodes[parent]; if (HasHigherOrEqualPriority(parentNode, node)) break; //节点更紧急, 将父节点向下移动腾出空间 _nodes[node.position] = parentNode; parentNode.position = node.position; node.position = parent; } _nodes[node.position] = node; } #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif private void CascadeDown(T node) { int finalQueueIndex = node.position; int childLeftIndex = 2 * finalQueueIndex; if (childLeftIndex > _numNodes) { return; } int childRightIndex = childLeftIndex + 1; T childLeft = _nodes[childLeftIndex]; if (HasHigherPriority(childLeft, node)) { if (childRightIndex > _numNodes) { node.position = childLeftIndex; childLeft.position = finalQueueIndex; _nodes[finalQueueIndex] = childLeft; _nodes[childLeftIndex] = node; return; } T childRight = _nodes[childRightIndex]; if (HasHigherPriority(childLeft, childRight)) { childLeft.position = finalQueueIndex; _nodes[finalQueueIndex] = childLeft; finalQueueIndex = childLeftIndex; } else { childRight.position = finalQueueIndex; _nodes[finalQueueIndex] = childRight; finalQueueIndex = childRightIndex; } } else if (childRightIndex > _numNodes) { return; } else { T childRight = _nodes[childRightIndex]; if (HasHigherPriority(childRight, node)) { childRight.position = finalQueueIndex; _nodes[finalQueueIndex] = childRight; finalQueueIndex = childRightIndex; } else { return; } } while (true) { childLeftIndex = 2 * finalQueueIndex; if (childLeftIndex > _numNodes) { node.position = finalQueueIndex; _nodes[finalQueueIndex] = node; break; } childRightIndex = childLeftIndex + 1; childLeft = _nodes[childLeftIndex]; if (HasHigherPriority(childLeft, node)) { if (childRightIndex > _numNodes) { node.position = childLeftIndex; childLeft.position = finalQueueIndex; _nodes[finalQueueIndex] = childLeft; _nodes[childLeftIndex] = node; break; } T childRight = _nodes[childRightIndex]; if (HasHigherPriority(childLeft, childRight)) { childLeft.position = finalQueueIndex; _nodes[finalQueueIndex] = childLeft; finalQueueIndex = childLeftIndex; } else { childRight.position = finalQueueIndex; _nodes[finalQueueIndex] = childRight; finalQueueIndex = childRightIndex; } } else if (childRightIndex > _numNodes) { node.position = finalQueueIndex; _nodes[finalQueueIndex] = node; break; } else { T childRight = _nodes[childRightIndex]; if (HasHigherPriority(childRight, node)) { childRight.position = finalQueueIndex; _nodes[finalQueueIndex] = childRight; finalQueueIndex = childRightIndex; } else { node.position = finalQueueIndex; _nodes[finalQueueIndex] = node; break; } } } } /// /// 对两个参数的优先级进行比较 /// /// 第一个参数 /// 第二个参数 /// /// 如果第一个参数的优先级大于第二个参数则返回true,否则返回false
/// 如果两个参数为同一个节点,返回false ///
#if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif private bool HasHigherPriority(T higher, T lower) { return (higher.priority < lower.priority); } /// /// 对两个参数的优先级进行比较 /// /// 第一个参数 /// 第二个参数 /// /// 如果第一个参数的优先级大于第二个参数则返回true,否则返回false
/// 如果两个参数为同一个节点,返回true ///
#if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif private bool HasHigherOrEqualPriority(T higher, T lower) { return (higher.priority <= lower.priority); } /// /// 队列头部出队
/// 如果队列为空则执行未定义的操作
/// O(log n) ///
/// 出队的元素 #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif public T Dequeue() { #if DEBUG if (_numNodes <= 0) { throw new InvalidOperationException("Cannot call Dequeue() on an empty queue"); } #endif T returnMe = _nodes[1]; //如果节点元素已经是最后一个节点,则直接移除 if (_numNodes == 1) { _nodes[1] = null; _numNodes = 0; return returnMe; } //将节点与最后一个节点对换 T formerLastNode = _nodes[_numNodes]; _nodes[1] = formerLastNode; formerLastNode.position = 1; _nodes[_numNodes] = null; _numNodes--; //将formerLastNode (不再是最后一个节点)向下冒泡 CascadeDown(formerLastNode); return returnMe; } /// /// 重新设置队列的大小,使其可以容纳更多的节点,当前的所有节点都会保留
/// 如果试图将队列大小设置成比当前队列中的数量小时,会执行未定义的操作
/// O(n) ///
public void Resize(int maxNodes) { #if DEBUG if (maxNodes <= 0) { throw new InvalidOperationException("Queue size cannot be smaller than 1"); } if (maxNodes < _numNodes) { throw new InvalidOperationException($"Called Resize({maxNodes}), but current queue contains { _numNodes } nodes"); } #endif T[] newArray = new T[maxNodes + 1]; int highestIndexToCopy = Math.Min(maxNodes, _numNodes); Array.Copy(_nodes, newArray, highestIndexToCopy + 1); _nodes = newArray; } /// /// 队列的第一个元素
/// 如果队列为空,则执行未定义的操作
/// O(1) ///
public T first { get { #if DEBUG if (_numNodes <= 0) { throw new InvalidOperationException("Cannot call .first on an empty queue"); } #endif return _nodes[1]; } } /// /// 更改队列里某个节点的优先级
/// 忘记调用这个方法会导致队列损坏!
/// 对不在这个队列中的节点元素调用这个方法会执行未定义的行为
/// O(log n) ///
#if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif public void UpdatePriority(T node, float priority) { #if DEBUG if (node == null) { throw new ArgumentNullException("node"); } if (!Contains(node)) { throw new InvalidOperationException($"Cannot call UpdatePriority() on a node which is not enqueued:{node}"); } #endif node.priority = priority; OnNodeUpdated(node); } #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif private void OnNodeUpdated(T node) { //按需向上或向下冒泡更新节点 int parentIndex = node.position >> 1; if (parentIndex > 0 && HasHigherPriority(node, _nodes[parentIndex])) { CascadeUp(node); } else { //如果 parentNode == node(node是根节点) 则会调用CascadeDown CascadeDown(node); } } /// /// 从队列中删除给定节点元素,这个节点不一定是队列的头
/// 如果节点并未在队列中,结果是未定义的,如果不确定,则先使用Contains()确认
/// O(log n) ///
#if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif public void Remove(T node) { #if DEBUG if (node == null) { throw new ArgumentNullException("node"); } if (!Contains(node)) { throw new InvalidOperationException($"Cannot call Remove() on a node which is not enqueued:{node}"); } #endif //如果节点元素已经是最后一个节点,则直接移除 if (node.position == _numNodes) { _nodes[_numNodes] = null; _numNodes--; return; } //将节点与最后一个节点对换 T formerLastNode = _nodes[_numNodes]; _nodes[node.position] = formerLastNode; formerLastNode.position = node.position; _nodes[_numNodes] = null; _numNodes--; //将formerLastNode (不再是最后一个节点)按需向上或者向下冒泡排序 OnNodeUpdated(formerLastNode); } /// /// 默认情况下有加入过一个队列的节点元素不能添加到另一个队列
/// 如果需要这么做,则在添加到另一个队列前调用当前队列的此方法
/// 如果节点当前在队列中或者属于其他队列,则结果是未定义的 ///
#if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif public void ResetNode(T node) { #if DEBUG if (node == null) { throw new ArgumentNullException("node"); } if (Contains(node)) { throw new InvalidOperationException("node.ResetNode was called on a node that is still in the queue"); } #endif node.position = 0; } /// /// 迭代器 /// /// 迭代器 public IEnumerator GetEnumerator() { #if NET_VERSION_4_5 // ArraySegment在4.5之前没有实现IEnumerable接口 IEnumerable e = new ArraySegment(_nodes, 1, _numNodes); return e.GetEnumerator(); #else for (int i = 1; i <= _numNodes; i++) yield return _nodes[i]; #endif } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } }