最小优先级队列(基于最小二叉堆算法)
2012-06-27 22:03 java线程例子 阅读(419) 评论(0) 编辑 收藏 举报在最小生成树Prim算法中,可以利用最小优先级队列来改善时间复杂度,同时在单源最短路径Dijkstra算法中也同样可以利用这种最小优先级队列来改善算法时间复杂度。实现最小优先级队列可以有很多种方式,比如基于二叉最小堆,或者斐波那契堆等。这里是二叉最小堆的C#实现,原理是根据书上的伪代码来的,但有些地方我做了改进,比如书key值改变,原来书上只能变大,这里取掉了这个限制。同时还提供了根据卫星值来选择元素的功能,下面是代码:
/// <summary> /// 队列元素包装类 /// </summary> /// <typeparam name="T">实际元素类型</typeparam> public class QueueElement<T> { /// <summary> /// Key值 /// </summary> public int KeyValue { get; internal set; } /// <summary> /// 实际对象 /// </summary> public T Element { get; private set; } public QueueElement(T Item, int KeyVal) { KeyValue = KeyVal; Element = Item; } } /// <summary> /// 最小优先级队列 /// </summary> /// <typeparam name="T"></typeparam> public class MinHeapQueue<T> { /// <summary> /// 队列元素存放,采用List实现. /// </summary> private List<QueueElement<T>> _queueValues = new List<QueueElement<T>>(); /// <summary> /// 队列元素数目 /// </summary> public int Count { get { return _queueValues.Count; } } /// <summary> /// 获取队列Key值最小的元素 /// </summary> /// <returns></returns> public T GetMinimum() { return _queueValues[0].Element; } /// <summary> /// 从队列中取出Key值最小的元素 /// </summary> /// <returns></returns> public T ExtractMin() { if (_queueValues.Count <= 0) { throw new Exception("队列为空"); } T theMin = _queueValues[0].Element; int theTail = Count - 1; _queueValues[0] = _queueValues[theTail]; _queueValues.RemoveAt(theTail); MinHeapify(0); return theMin; } /// <summary> /// 整理堆元素,保持最小堆特性,这个函数跟DownAdjust功能相同 /// </summary> /// <param name="i"></param> public void MinHeapify(int i) { int HeapSize = Count; int theL = HeapL(i); int theR = HeapR(i); int theLeast = i; if (theL < HeapSize && _queueValues[theL].KeyValue < _queueValues[theLeast].KeyValue) { theLeast = theL; } if (theR < HeapSize && _queueValues[theR].KeyValue < _queueValues[theLeast].KeyValue) { theLeast = theR; } if (theLeast != i) { SwapElement(i, theLeast); MinHeapify(theLeast); } } /// <summary> /// 改变元素key值 /// </summary> /// <param name="SelectFunc"></param> /// <param name="NewKey"></param> public void ChangeKey(Func<T, bool> SelectFunc, int NewKey) { int theIndex = -1; for (int i = 0; i < Count; i++) { if (SelectFunc(_queueValues[i].Element) == true) { theIndex = i; break; } } if (theIndex < 0) { return; } if (_queueValues[theIndex].KeyValue < NewKey) { _queueValues[theIndex].KeyValue = NewKey; DownAdjust(theIndex); return; } if (_queueValues[theIndex].KeyValue > NewKey) { _queueValues[theIndex].KeyValue = NewKey; UpAdjust(theIndex); return; } } /// <summary> /// 沿树根方向整理元素,保持最小堆特性 /// </summary> /// <param name="i"></param> private void UpAdjust(int i) { int theIndex = i; int thePIndex = HeapP(theIndex); while (thePIndex >= 0 && _queueValues[theIndex].KeyValue < _queueValues[thePIndex].KeyValue) { SwapElement(thePIndex, theIndex); theIndex = thePIndex; thePIndex = HeapP(theIndex); } } /// <summary> /// 沿树叶方向整理元素,保持最小堆特性 /// </summary> /// <param name="i"></param> private void DownAdjust(int i) { int HeapSize = Count; int theL = HeapL(i); int theR = HeapR(i); int theLeast = i; if (theL < HeapSize && _queueValues[theL].KeyValue < _queueValues[theLeast].KeyValue) { theLeast = theL; } if (theR < HeapSize && _queueValues[theR].KeyValue < _queueValues[theLeast].KeyValue) { theLeast = theR; } if (theLeast != i) { SwapElement(i, theLeast); DownAdjust(theLeast); } } /// <summary> /// 改变元素key值 /// </summary> /// <param name="i"></param> /// <param name="NewKey"></param> public void ChangeKey(int i, int NewKey) { int theIndex = i; if (_queueValues[theIndex].KeyValue > NewKey) { _queueValues[theIndex].KeyValue = NewKey; UpAdjust(theIndex); return; } if (_queueValues[theIndex].KeyValue < NewKey) { _queueValues[theIndex].KeyValue = NewKey; DownAdjust(theIndex); return; } } /// <summary> /// 删除队列元素 /// </summary> /// <param name="SelectFunc"></param> public void HeapDelete(Func<T, bool> SelectFunc) { int theIndex = -1; for (int i = 0; i < Count; i++) { if (SelectFunc(_queueValues[i].Element) == true) { theIndex = i; break; } } if (theIndex < 0) { return; } SwapElement(theIndex, Count - 1); _queueValues.RemoveAt(Count - 1); if (theIndex < Count) { int theP = HeapP(theIndex); bool theUp = false; if (theP >= 0) { if (_queueValues[theIndex].KeyValue < _queueValues[theP].KeyValue) { UpAdjust(theIndex); theUp = true; } } if (theUp == false) { MinHeapify(theIndex); } } } /// <summary> /// 队列元素交换位置 /// </summary> /// <param name="i"></param> /// <param name="j"></param> private void SwapElement(int i, int j) { QueueElement<T> theTmp = _queueValues[i]; _queueValues[i] = _queueValues[j]; _queueValues[j] = theTmp; } /// <summary> /// 将元素插入队列 /// </summary> /// <param name="Element"></param> /// <param name="Key"></param> public void HeapInsert(T Element, int Key) { _queueValues.Add(new QueueElement<T>(Element, int.MinValue)); ChangeKey(Count - 1, Key); } /// <summary> /// 取节点的左孩子节点 /// </summary> /// <param name="i"></param> /// <returns></returns> private int HeapL(int i) { return i * 2 + 1; } /// <summary> /// 取节点的右孩子节点 /// </summary> /// <param name="i"></param> /// <returns></returns> private int HeapR(int i) { return i * 2 + 2; } /// <summary> /// 取节点的父节点 /// </summary> /// <param name="i"></param> /// <returns></returns> private int HeapP(int i) { return (i + 1) / 2 - 1; } }
需要注意的,我前面有篇基于二叉最大堆的优先级队列算法跟这篇很类似,但上篇算法中有小错误,而这篇算法中的优先级队列已通过测试,没问题。大家可对比一下,看错误在哪里。
Ps:既然到首页,还是加点注释.