基于堆的最大最小优先级队列的实现
最大堆能够在O(1)的时间内取得集合中的最大值,并且在集合中加入新元素的时候,能够以O(Logn)的时间将新的元素插入到堆中。
当取出最大的元素时,能够以O(Logn)的时间重新将堆整理成最大堆。最小堆同理。
最大优先级队列的应用实例:基于优先级的作业调度,在所有等待调度的作业中,选择具有最大优先级作业进行处理。同时一个新的作业也可以插入到队列里面去。
例如可以实现自己的基于优先级的多线程作业调度程序。
最小优先级队列的应用实例:可以实现一个基于时间的作业调度程序,时间最小的被优先选择进行事件通知或者处理。Huffman编码的实现可以依靠最小优先级队列实现。
最大最小优先级队列的C#实现:
队列处理的数据类型:
public interface IHeapValue { int Value { get; set; } }
最大优先级队列:
public class MaxPriorityQueue<TNode> where TNode : IHeapValue { private TNode[] array; //cursor 指向第一个空出来的位置 private int cursor; public MaxPriorityQueue() { array = new TNode[32]; cursor = 0; } public bool IsEmpty { get { return cursor <=0; } } public void Insert(TNode x) { if (cursor + 1 == array.Count()) { TNode[] tmparray = new TNode[array.Count() * 2]; array.CopyTo(tmparray, 0); array = tmparray; } //往上检查是否成最大堆 int xIndex = cursor++; array[xIndex] = x; while (xIndex / 2 >= 0) { if (array[xIndex / 2].Value >= array[xIndex].Value) break; TNode tmpNode = array[xIndex / 2]; array[xIndex / 2] = array[xIndex]; array[xIndex] = tmpNode; xIndex = xIndex / 2; } } public TNode Maximum() { return array[0]; } public TNode ExtractMax() { TNode hn = array[0]; //把最后一个元素换到第一个 array[0]= array[cursor-1],array[cursor-1]=null;cursor--; array[0] = array[cursor - 1]; array[cursor - 1] = default(TNode); cursor--; maxHeapify(0, cursor - 1, 0); return hn; } public void IncreaseKey(int nodeIndex, int newValue) { if (nodeIndex < cursor && array[nodeIndex].Value < newValue) { array[nodeIndex].Value = newValue; while (nodeIndex / 2 >= 0) { if (array[nodeIndex / 2].Value >= array[nodeIndex].Value) break; TNode tmpNode = array[nodeIndex / 2]; array[nodeIndex / 2] = array[nodeIndex]; array[nodeIndex] = tmpNode; nodeIndex = nodeIndex / 2; } } } //由下向上建堆时使用此函数,下面已经建好,上面还没好时使用 private void maxHeapify(int startIndex, int endIndex, int newRootIndex) { //int L = (newRootIndex - startIndex) * 2 + 1 + startIndex; int L = (newRootIndex - startIndex + 1) * 2 + startIndex - 1;//The array base is from 0. int R = L + 1; int tmpLargestIndex = newRootIndex; if (L <= endIndex && array[L].Value.CompareTo(array[tmpLargestIndex].Value) > 0) { tmpLargestIndex = L; } if (R <= endIndex && array[R].Value.CompareTo(array[tmpLargestIndex].Value) > 0) { tmpLargestIndex = R; } if (tmpLargestIndex != newRootIndex) { //swap array[tmpLargestIndex] and array[newRootIndex] TNode tmpT = array[tmpLargestIndex]; array[tmpLargestIndex] = array[newRootIndex]; array[newRootIndex] = tmpT; //MaxHeapify the child branch, the newRootIndex= tmpLargestIndex maxHeapify(startIndex, endIndex, tmpLargestIndex); } } }
最小优先级队列:
public class MinPriorityQueue<TNode> where TNode : IHeapValue { private TNode[] array; //cursor 指向第一个空出来的位置 private int cursor; public MinPriorityQueue() { array = new TNode[32]; cursor = 0; } public bool IsEmpty { get { return cursor <= 0; } } public void Insert(TNode x) { if (cursor + 1 == array.Count()) { TNode[] tmparray = new TNode[array.Count() * 2]; array.CopyTo(tmparray, 0); array = tmparray; } //往上检查是否成最小堆 int xIndex = cursor++; array[xIndex] = x; while (xIndex / 2 >= 0) { if (array[xIndex / 2].Value <= array[xIndex].Value) break; TNode tmpNode = array[xIndex / 2]; array[xIndex / 2] = array[xIndex]; array[xIndex] = tmpNode; xIndex = xIndex / 2; } } public TNode Minimum() { return array[0]; } public TNode ExtractMin() { TNode hn = array[0]; //把最后一个元素换到第一个 array[0]= array[cursor-1],array[cursor-1]=null;cursor--; array[0] = array[cursor - 1]; array[cursor - 1] = default(TNode); cursor--; minHeapify(0, cursor - 1, 0); return hn; } public void DecreaseKey(int nodeIndex, int newValue) { if (nodeIndex < cursor && array[nodeIndex].Value < newValue) { array[nodeIndex].Value = newValue; while (nodeIndex / 2 >= 0) { if (array[nodeIndex / 2].Value <= array[nodeIndex].Value) break; TNode tmpNode = array[nodeIndex / 2]; array[nodeIndex / 2] = array[nodeIndex]; array[nodeIndex] = tmpNode; nodeIndex = nodeIndex / 2; } } } //由下向上建堆时使用此函数,下面已经建好,上面还没好时使用 private void minHeapify(int startIndex, int endIndex, int newRootIndex) { //int L = (newRootIndex - startIndex) * 2 + 1 + startIndex; int L = (newRootIndex - startIndex + 1) * 2 + startIndex - 1;//The array base is from 0. int R = L + 1; int tmpLargestIndex = newRootIndex; if (L <= endIndex && array[L].Value.CompareTo(array[tmpLargestIndex].Value) < 0) { tmpLargestIndex = L; } if (R <= endIndex && array[R].Value.CompareTo(array[tmpLargestIndex].Value) < 0) { tmpLargestIndex = R; } if (tmpLargestIndex != newRootIndex) { //swap array[tmpLargestIndex] and array[newRootIndex] TNode tmpT = array[tmpLargestIndex]; array[tmpLargestIndex] = array[newRootIndex]; array[newRootIndex] = tmpT; //MaxHeapify the child branch, the newRootIndex= tmpLargestIndex minHeapify(startIndex, endIndex, tmpLargestIndex); } } }
基于控制台输出的测试调用方法:
MaxPriorityQueue<IHeapValue> maxheap = new MaxPriorityQueue<IHeapValue>(); MinPriorityQueue<IHeapValue> minheap = new MinPriorityQueue<IHeapValue>(); List<IHeapValue> list = new List<IHeapValue>(); Random rnd = new Random(DateTime.Now.Millisecond); for (int i = 0; i < 10; i++) { HeapNode hn = new HeapNode() { Value = rnd.Next(0, 100) }; list.Add(hn); maxheap.Insert(hn); minheap.Insert(hn); } Console.WriteLine("RandomData:"); list.ForEach(n => Console.Write("{0},", n.Value)); Console.WriteLine(Environment.NewLine + "MaxHeapOutput:"); while (!maxheap.IsEmpty) { Console.Write("{0},", maxheap.ExtractMax().Value); } Console.WriteLine(Environment.NewLine + "MinHeapOutput:"); while (!minheap.IsEmpty) { Console.Write("{0},", minheap.ExtractMin().Value); } Console.ReadKey();
输出:
作者:Andy Zeng
欢迎任何形式的转载,但请务必注明出处。