算法导论第六章优先队列(二)
2015-09-20 17:16
489 查看
优先队列可以说是堆的一个非常重要的应用,和堆对应,优先队列也分最小优先队列和最大优先队列。
优先队列是一种用来维护由一组元素构成的集合S的数据结构,其中每一个元素都有一个关键字(key),关键字赋予了一个元素的优先级,故名为优先队列。之所以用堆来实现优先队列,我想最大的原因是堆很容易对元素按关键字进行排序。
优先队列的应用:
最大优先队列:其中最为典型的就是“共享计算机系统的作业调度”,通过记录各个作业的优先级,来调度一个作业的执行、删除和插入等操作。
最小优先队列:可以被用于“基于事件驱动的模拟器”,队列中保存要模拟的事件,每个事件都有一个发生时间作为关键字。事件必须按发生的时间顺序进行模拟,因为某一事件的模拟结果可能会触发对其他事件的模拟。
优先队列的实现:
为了实现优先队列,需要实现这样的几个过程:
1)Insert(S, x):插入x到集合S中;
2)Maximum(S):返回S中具有最大关键字的元素;
3)Extract_Max(S):去掉并返回集合S中具有最大关键字的元素;
4)Increase_Key(S, x, key):将元素x的关键字增加到key。
我们暂且不用管这些奇怪的函数为什么要这么定义,因为这是前人的成功经验总结,肯定是在实际应用中这几个函数用得是最多的,总之,知道这样的四个函数就行了,等用到的时候就知道它们的好处了。
首先,基于堆,Maximum可以在O(1)的时间内完成,如:
其次,Extract_Max(S)和Maximum()的区别就在于,得到了之后还要删除,在不改变结构的情况下,最好的删除方法就是用最后一个元素来代替第一个元素,但是要注意,删除之后,有可能堆的性质就不能保证了,所以,这个时候调用Max_Heapify()调整一下。如下:
对于Increase_Key(S, x, key),我们直接用Key替换X,但是替换之后堆的性质也可能改变了,可以知道的是,X后面的元素仍然满足堆的性质,因为Key>X,这时就之用维护X前面的元素,一层层往上调用Max_Heapify()即可,如:
最后,Insert(S, x)操作,我们可以在最后增加一个-∞的元素,然后将其转换成将-∞增加到x,即转换成Increase_Key(S, -∞, x)。如:
除此之外,习题6.5-8要求在O(lgn)的时间内实现一个Delete(S, i)操作。很容易想到相当于对A[i]为根的堆进行Extract_Max()操作。如:
以上所有的操作,除了Maximum()之外,其余所有的函数的时间复杂度皆为O(lgn),所以,这也是为什么用堆来实现优先队列一个非常重要的原因。下面给出一个非常简单的优先队列的实现(元素的值就是Key)。
View Code
优先队列是一种用来维护由一组元素构成的集合S的数据结构,其中每一个元素都有一个关键字(key),关键字赋予了一个元素的优先级,故名为优先队列。之所以用堆来实现优先队列,我想最大的原因是堆很容易对元素按关键字进行排序。
优先队列的应用:
最大优先队列:其中最为典型的就是“共享计算机系统的作业调度”,通过记录各个作业的优先级,来调度一个作业的执行、删除和插入等操作。
最小优先队列:可以被用于“基于事件驱动的模拟器”,队列中保存要模拟的事件,每个事件都有一个发生时间作为关键字。事件必须按发生的时间顺序进行模拟,因为某一事件的模拟结果可能会触发对其他事件的模拟。
优先队列的实现:
为了实现优先队列,需要实现这样的几个过程:
1)Insert(S, x):插入x到集合S中;
2)Maximum(S):返回S中具有最大关键字的元素;
3)Extract_Max(S):去掉并返回集合S中具有最大关键字的元素;
4)Increase_Key(S, x, key):将元素x的关键字增加到key。
我们暂且不用管这些奇怪的函数为什么要这么定义,因为这是前人的成功经验总结,肯定是在实际应用中这几个函数用得是最多的,总之,知道这样的四个函数就行了,等用到的时候就知道它们的好处了。
首先,基于堆,Maximum可以在O(1)的时间内完成,如:
int PriorityQueue::HeapMaximum() //return the maximum key from priority queue; { return GetQueueElement(0); //the first element is max; }
其次,Extract_Max(S)和Maximum()的区别就在于,得到了之后还要删除,在不改变结构的情况下,最好的删除方法就是用最后一个元素来代替第一个元素,但是要注意,删除之后,有可能堆的性质就不能保证了,所以,这个时候调用Max_Heapify()调整一下。如下:
int PriorityQueue::HeapExtractMax() //delete and return the maximum key from queue; { if (IsEmptyHeap()) throw "heap underflow"; int heap_size = GetHeapSize(); int maxNum = GetQueueElement(0); SetQueueElement(0, GetQueueElement(heap_size-1)); //A[1] = A[heap_size] SetHeapSizeMinus1(); MaxHeapify(0); //Max_Heapify() return maxNum; }
对于Increase_Key(S, x, key),我们直接用Key替换X,但是替换之后堆的性质也可能改变了,可以知道的是,X后面的元素仍然满足堆的性质,因为Key>X,这时就之用维护X前面的元素,一层层往上调用Max_Heapify()即可,如:
void PriorityQueue::HeapIncreaseKey(int srcIndex, int dstKey) //increasing the srcKey to dstKey { if (dstKey < GetQueueElement(srcIndex)) throw "new key is smaller than current key!"; SetQueueElement(srcIndex, dstKey); //x = key while(srcIndex > 0 && GetQueueElement(getParent(srcIndex)) < GetQueueElement(srcIndex)) { Swap(srcIndex, getParent(srcIndex)); srcIndex = getParent(srcIndex); //get parent } }
最后,Insert(S, x)操作,我们可以在最后增加一个-∞的元素,然后将其转换成将-∞增加到x,即转换成Increase_Key(S, -∞, x)。如:
void PriorityQueue::HeapInsert(int key) //insert key to the priority queue; { AddQueueElement(INT_MIN); //add the INT_MIN to the end of heapQueue; int heap_size = GetHeapSize(); HeapIncreaseKey(heap_size-1, key); }
除此之外,习题6.5-8要求在O(lgn)的时间内实现一个Delete(S, i)操作。很容易想到相当于对A[i]为根的堆进行Extract_Max()操作。如:
Heap-Delete(A, i) A[i] = A[A.heap-size] A.heap-size = A.heap-size - 1 Heapify(A, i)
以上所有的操作,除了Maximum()之外,其余所有的函数的时间复杂度皆为O(lgn),所以,这也是为什么用堆来实现优先队列一个非常重要的原因。下面给出一个非常简单的优先队列的实现(元素的值就是Key)。
//MinHeap_KMerge.cpp #include <iostream> #include <vector> using namespace std; #include "MinHeap.h" //merge the k list to a heap; template<class T> MinHeap<T>::MinHeap(size_t kSize) { if (!m_minHeap) delete []m_minHeap; m_minHeap = new T[kSize+1]; m_heapSize = 0; } //adjust the min heap; template<class T> void MinHeap<T>::MinHeapify(size_t index) { //assert size_t heap_size = GetHeapSize(); while (true) { size_t left = LEFT(index); size_t right = RIGHT(index); size_t smallest; if (left < heap_size && HeapCompare(left, index)) smallest = left; else smallest = index; if (right < heap_size && HeapCompare(right, smallest)) smallest = right; if (smallest != index) { Swap(index, smallest); index = smallest; } else break; } } //insert element template<class T> void MinHeap<T>::HeapInsert(const T &element) { m_minHeap[m_heapSize] = element; m_heapSize += 1; size_t index = m_heapSize-1; while (index > 0 && HeapCompare(index, PARENT(index))) { Swap(index, PARENT(index)); index = PARENT(index); } } //return and delete the min element template<class T> T MinHeap<T>::HeapExtractMin() { if (IsEmptyHeap()) throw "Heap is Empty!"; T minElement = HeapMin(); int heap_size = GetHeapSize(); m_minHeap[0] = m_minHeap[heap_size-1]; m_heapSize -= 1; MinHeapify(0); return minElement; } //return min element; template<class T> T MinHeap<T>::HeapMin() const { return m_minHeap[0]; } int main() { const size_t k = 3; vector<int> vecList[k]; vector<int>::iterator iterList[k]; vector<int> vecSort; vector<int>::iterator iterS; vector<int>::iterator it; MinHeap<vector<int>::iterator> minHeap(k); //first list vecList[0].push_back(12); vecList[0].push_back(24); vecList[0].push_back(52); cout << "first list:" << endl; for ( it = vecList[0].begin();it != vecList[0].end(); ++it) cout << *it << "->"; cout << "NULL" << endl; vecList[1].push_back(9); vecList[1].push_back(32); cout << "second list:" << endl; for ( it = vecList[1].begin();it != vecList[1].end(); ++it) cout << *it << "->"; cout << "NULL" << endl; vecList[2].push_back(34); vecList[2].push_back(42); vecList[2].push_back(78); cout << "third list:" << endl; for ( it = vecList[2].begin();it != vecList[2].end(); ++it) cout << *it << "->"; cout << "NULL" << endl; iterList[0] = vecList[0].begin(); iterList[1] = vecList[1].begin(); iterList[2] = vecList[2].begin(); minHeap.HeapInsert(iterList[0]); minHeap.HeapInsert(iterList[1]); minHeap.HeapInsert(iterList[2]); while(minHeap.GetHeapSize()) { it = minHeap.HeapExtractMin(); vecSort.push_back(*it); ++it; if (it != vecList[0].end() && it != vecList[1].end() && it != vecList[2].end()) { //!!!!Expression vector iterators incompatible minHeap.HeapInsert(it); } } cout << "merge:" << endl; for (iterS = vecSort.begin(); iterS != vecSort.end(); ++ iterS) cout << *iterS << "->"; cout << "NULL" << endl; return 0; }
View Code
相关文章推荐
- 继承与多态
- Android中正确获得View控件的宽和高——使用篇
- 如何绘制方形渐开线
- 上千个主分片--Kagillion Shards--es横向扩展设计
- 版本控制系统(VCS→DVCS)
- The Balance 1709 (母函数 技巧(相加和相减)) 好题
- Activity,intent,bundle,请求码,结果码,服务,广播
- VBend、unload、exit sub、 end sub、close、hide的比较
- 《大道至简》第一章读后感
- 学习日志---动态规划(背包问题)
- Codeblocks的编译器配置
- Servlet读取资源文件的三种方式
- 实现顶部轮播,下部listview经典布局的两种方式
- 主分片平衡--Shard Overallocation--es横向扩展设计
- Crisis of HDU(母函数)
- 表驱动法
- 2015 ACM-ICPC 沈阳网络赛总结
- sublime安装与配置
- iOS开发笔记--UISlider的相关属性设置
- docker学习笔记(一)