SOURCE:http://www.cnblogs.com/skyivben/archive/2009/04/18/1438731.html
优先队列(priority queue) 是很重要的数据结构。我在做 ACM 题时就经常要用到她。C++ STL 就包括 priority_queue 。Java 也有 PriorityQueue 类。遗憾的是,.NET Framework Base Class Library 中并不包括优先队列。于是,我只好自己用 C# 语言写一个,如下所示:
using System; using System.Collections.Generic; namespace Skyiv.Util { class PriorityQueue<T> { IComparer<T> comparer; T[] heap; public int Count { get; private set; } public PriorityQueue() : this(null) { } public PriorityQueue(int capacity) : this(capacity, null) { } public PriorityQueue(IComparer<T> comparer) : this(16, comparer) { } public PriorityQueue(int capacity, IComparer<T> comparer) { this.comparer = (comparer == null) ? Comparer<T>.Default : comparer; this.heap = new T[capacity]; } public void Push(T v) { if (Count >= heap.Length) Array.Resize(ref heap, Count * 2); heap[Count] = v; SiftUp(Count++); } public T Pop() { var v = Top(); heap[0] = heap[--Count]; if (Count > 0) SiftDown(0); return v; } public T Top() { if (Count > 0) return heap[0]; throw new InvalidOperationException("优先队列为空"); } void SiftUp(int n) { var v = heap[n]; for (var n2 = n / 2; n > 0 && comparer.Compare(v, heap[n2]) > 0; n = n2, n2 /= 2) heap[n] = heap[n2]; heap[n] = v; } void SiftDown(int n) { var v = heap[n]; for (var n2 = n * 2; n2 < Count; n = n2, n2 *= 2) { if (n2 + 1 < Count && comparer.Compare(heap[n2 + 1], heap[n2]) > 0) n2++; if (comparer.Compare(v, heap[n2]) >= 0) break; heap[n] = heap[n2]; } heap[n] = v; } } }
如上所示,这个 PriorityQueue<T>
泛型类提供四个公共构造函数,第一个是无参的构造函数,其余的构造函数允许指定优先队列中包括的初始元素数(capacity)、如何对键进行比较(comparer)。
这个程序使用堆(heap)来实现优先队列。所以,所需的空间是最小的。Count 属性和 Top 方法的时间复杂度是 O(1),Push 和 Pop 方法的时间复杂度都是 O(logN)。
我曾经用 List<T> 泛型类实现过一个优先队列,请参见我的博客 Timus1016. A Cube on the Walk 。虽然更简单,程序代码只有 23 行,但是效率不高,其 Push 和 Pop 方法的时间复杂度都是 O(N)。
@DiryBoy
我也用 Reflector 查了一下 .NET Framework 3.5 Base Class Library 的源代码,发现以下相关的类:
System.Workflow.Runtime.KeyedPriorityQueue<K,V,P>
System.Windows.Threading.PriorityQueue<T>
MS.Internal.PriorityQueue<T>
她们分别位于以下程序集:
Sysem.Workflow.Runtime, Version=3.0.0.0
WindowsBase, Version=3.0.0.0
PresentationCore, Version=3.0.0.0
她们都是 internal 的类,因此我们无法使用。
她们都是直接从 object 类派生的,都没有实现任何接口,也都比较简单。(看来在3楼的估计有误)
第二个类主要用于线程优先级调度。第三个类就是标准的优先队列了。
回复 引用 查看
我也用 Reflector 查了一下 .NET Framework 3.5 Base Class Library 的源代码,发现以下相关的类:
System.Workflow.Runtime.KeyedPriorityQueue<K,V,P>
System.Windows.Threading.PriorityQueue<T>
MS.Internal.PriorityQueue<T>
她们分别位于以下程序集:
Sysem.Workflow.Runtime, Version=3.0.0.0
WindowsBase, Version=3.0.0.0
PresentationCore, Version=3.0.0.0
她们都是 internal 的类,因此我们无法使用。
她们都是直接从 object 类派生的,都没有实现任何接口,也都比较简单。(看来在3楼的估计有误)
第二个类主要用于线程优先级调度。第三个类就是标准的优先队列了。
回复 引用 查看
using System; using System.Collections.Generic; namespace MS.Internal { internal class PriorityQueue<T> { // Fields private IComparer<T> _comparer; private int _count; private T[] _heap; private const int DefaultCapacity = 6; // Methods internal PriorityQueue(int capacity, IComparer<T> comparer) { this._heap = new T[(capacity > 0) ? capacity : 6]; this._count = 0; this._comparer = comparer; } private static int HeapLeftChild(int i) { return ((i * 2) + 1); } private static int HeapParent(int i) { return ((i - 1) / 2); } private static int HeapRightFromLeft(int i) { return (i + 1); } internal void Pop() { if (this._count > 1) { int i = 0; for (int j = PriorityQueue<T>.HeapLeftChild(i); j < this._count; j = PriorityQueue<T>.HeapLeftChild(i)) { int index = PriorityQueue<T>.HeapRightFromLeft(j); int num4 = ((index < this._count) && (this._comparer.Compare(this._heap[index], this._heap[j]) < 0)) ? index : j; this._heap[i] = this._heap[num4]; i = num4; } this._heap[i] = this._heap[this._count - 1]; } this._count--; } internal void Push(T value) { if (this._count == this._heap.Length) { T[] localArray = new T[this._count * 2]; for (int j = 0; j < this._count; j++) { localArray[j] = this._heap[j]; } this._heap = localArray; } int i = this._count; while (i > 0) { int index = PriorityQueue<T>.HeapParent(i); if (this._comparer.Compare(value, this._heap[index]) >= 0) { break; } this._heap[i] = this._heap[index]; i = index; } this._heap[i] = value; this._count++; } // Properties internal int Count { get { return this._count; } } internal T Top { get { return this._heap[0]; } } } }
回复 引用 查看
@非主流程序员
这正是我在下一篇随笔:
http://www.cnblogs.com/skyivben/archive/2009/04/19/1439154.html
中实现的 KeyedPriorityQueue 类所做的事情。
在那篇随笔中,需要实现一个内存管理器,而 KeyedPriorityQueue 类用来保存已经分配的“内存块”。当操作系统发出一个访问指定编号(Id)的内存块的请求时,就需要根据该编号(Id)在该优先队列中查找“内存块”(bool ContainsKey(int id))。如果找到该“内存块”,还需要更新其到期时间(Update(Block v))。
不写注释是因为代码本身已经是自注释的了,变量名和方法名都是有意义的。随笔中也做了少量的说明。“堆(heap)”是著名的数据结构,可以在任何一本讲数据结构和算法的书中找到详细的说明。注释也无法解释得更清楚。
回复 引用 查看
这正是我在下一篇随笔:
http://www.cnblogs.com/skyivben/archive/2009/04/19/1439154.html
中实现的 KeyedPriorityQueue 类所做的事情。
在那篇随笔中,需要实现一个内存管理器,而 KeyedPriorityQueue 类用来保存已经分配的“内存块”。当操作系统发出一个访问指定编号(Id)的内存块的请求时,就需要根据该编号(Id)在该优先队列中查找“内存块”(bool ContainsKey(int id))。如果找到该“内存块”,还需要更新其到期时间(Update(Block v))。
不写注释是因为代码本身已经是自注释的了,变量名和方法名都是有意义的。随笔中也做了少量的说明。“堆(heap)”是著名的数据结构,可以在任何一本讲数据结构和算法的书中找到详细的说明。注释也无法解释得更清楚。
回复 引用 查看
评论