数据结构:优先队列
2017-10-12 17:01
183 查看
一般我们前面介绍的队列,队列的一个特性是先进先出。但是在作业调度的过程中我们总是希望很短的作业可以优先处理,这样我们就不用一味的等待短的作业而花费很长的时间去处理。但是同时有些短的但是很重要的作业也应该享有优先权。
优先队列至少允许以下两种操作,insert(插入)和 deleteMin(删除最小项)。insert 操作等同于 enqueue(入队),而 deleteMin 则是队列操作的 dequeue(出队)在优先级队列中的等价操作。
二叉堆实现:
我们一般称二叉堆为堆,堆有两个性质,堆序性质和结构性质。堆是一棵被完全填满的二叉树,例外在最底层,底层元素从左到右填充。这样的树被称为完全二叉树。对于数组中任意位置 i 上的元素,其左儿子在 2i 上,右儿子也就在 2i+1 上,它的父亲则则在 floor(i/2)
堆序性质:使操作可以快速的执行的性质是堆序性质。根据堆的性质最小元总是可以在根部找到。因此实现 insert 和 deleteMin 操作是很容易的,所有的工作需要保证始终保持堆序的性质。
insert 操作:
将一个元素 X 插入到队中,我们在下一个空闲位置创建一个空穴,因为否则该堆将不是完全树。如果 X 可以放入空穴而不破坏堆序,那么插入完成。否则,把空穴的父结点上的元素移入空穴中,这样,空穴朝着根的方向向上行了一步。继续该过程直到 X 能被放入空穴中为止。这种策略也叫做上滤(percolate up)
类似的我们也可以声明一个最大堆,它使我们通过改变堆序性质能够有效的找出和删除最大元。因此,优先队列可以用来找出最大元和最小元,但这需要提前确定。
如果要插入的元素是新的最小的元素从而一直上滤到根处,那么这种插入时间为 O(logN)。
2.deleteMin 操作:
deleteMin 的操作类似于 insert,首先找到最小元素是比较简单的,难的在于删除它,因为一旦删除堆顶的元素那么就会破坏堆序性质,因此我们需要重新调整。具体操作的方法是:当删除最小的元素,要在根结点处建立一个空穴。由于现在堆少了一个元素,因此堆中最后一个元素 X 必须移动到该堆的某个地方。如果 X 可以被放在空穴处则删除操作完成;如果不行,则将空穴的两个儿子中较小的移入空穴,这样就可以把空穴往下推一层。重复该步骤直到 X 可以被放入空穴中。因此我们的做法是将 X 置入沿着从根开始包含最小儿子的一条路径上的一个正确位置。这种策略叫做下滤(percolate down)
优先队列至少允许以下两种操作,insert(插入)和 deleteMin(删除最小项)。insert 操作等同于 enqueue(入队),而 deleteMin 则是队列操作的 dequeue(出队)在优先级队列中的等价操作。
二叉堆实现:
我们一般称二叉堆为堆,堆有两个性质,堆序性质和结构性质。堆是一棵被完全填满的二叉树,例外在最底层,底层元素从左到右填充。这样的树被称为完全二叉树。对于数组中任意位置 i 上的元素,其左儿子在 2i 上,右儿子也就在 2i+1 上,它的父亲则则在 floor(i/2)
template <typename Comparable> class BinaryHeap { public: explicit BinaryHeap(int capacity = 100); explicit BinaryHeap(const vector<Comparable>& items); bool isEmpty() const; const Comparable& findMin() const; void insert(const Comparable& x); void deleteMin(); void deleteMin(Comparable& minItem); void makeEmpty(); private: int currentSize; vector<Comparable> array; void buildHeap(); void percolateDown(int hole); } 一个堆的数据结构将由一个数组和一个代表当前堆大小的整数组成。
堆序性质:使操作可以快速的执行的性质是堆序性质。根据堆的性质最小元总是可以在根部找到。因此实现 insert 和 deleteMin 操作是很容易的,所有的工作需要保证始终保持堆序的性质。
insert 操作:
将一个元素 X 插入到队中,我们在下一个空闲位置创建一个空穴,因为否则该堆将不是完全树。如果 X 可以放入空穴而不破坏堆序,那么插入完成。否则,把空穴的父结点上的元素移入空穴中,这样,空穴朝着根的方向向上行了一步。继续该过程直到 X 能被放入空穴中为止。这种策略也叫做上滤(percolate up)
类似的我们也可以声明一个最大堆,它使我们通过改变堆序性质能够有效的找出和删除最大元。因此,优先队列可以用来找出最大元和最小元,但这需要提前确定。
void insert(const Comparable& x) { if(currentSize == array.size()-1) array.resize(array.size()*2); int hole = ++currentSize; for(;hole>1&&x<array[hole/2];hole/=2) array[hole] = array[hole/2]; array[hole] = x;
如果要插入的元素是新的最小的元素从而一直上滤到根处,那么这种插入时间为 O(logN)。
2.deleteMin 操作:
deleteMin 的操作类似于 insert,首先找到最小元素是比较简单的,难的在于删除它,因为一旦删除堆顶的元素那么就会破坏堆序性质,因此我们需要重新调整。具体操作的方法是:当删除最小的元素,要在根结点处建立一个空穴。由于现在堆少了一个元素,因此堆中最后一个元素 X 必须移动到该堆的某个地方。如果 X 可以被放在空穴处则删除操作完成;如果不行,则将空穴的两个儿子中较小的移入空穴,这样就可以把空穴往下推一层。重复该步骤直到 X 可以被放入空穴中。因此我们的做法是将 X 置入沿着从根开始包含最小儿子的一条路径上的一个正确位置。这种策略叫做下滤(percolate down)
void deleteMin() { if(isEmpty()) throw UnderflowException(); array[1] = array[currentSize--]; percolateDown(1); } void deleteMin(Comparable& minItem) { if(isEmpty()) throw UnderflowException(); minItem = array[1]; array[1] = array[currentSize--]; percolateDown(1); } void percolateDown(int hole) { int child; Comparable tmp = array[hole]; for(;hole*2<=currentSize; hole = child) { child = hole * 2; if(child!=currentSize&&array[child+1]<array[child]) ++child; if(array[child]<tmp) array[hole] = array[child]; else break; } array[hole] = tmp; }
相关文章推荐
- uva 11995 栈,队列,优先队列,等基本数据结构的应用与理解
- C++数据结构 之 优先队列_Priority Queue
- 常用数据结构STL实现(优先队列、队列、栈)
- [置顶] 【数据结构】【C++STL】动态数组 集合 映射和优先队列
- 堆数据结构+堆排序+最大优先队列的堆的实现
- 【数据结构】回顾优先队列(堆)
- 《挑战程序设计竞赛》2.4.1 数据结构-优先队列 POJ2431 3253 3614 2010(3)
- 数据结构_优先队列
- 数据结构【三】:简单优先队列PriorityQueue
- 【数据结构】实现大小堆也叫二叉堆(类似c++中的优先队列)
- 数据结构-优先队列
- 数据结构(四)之优先队列(堆)
- [数据结构]第九章-优先队列
- 数据结构之优先队列--二叉堆(Java实现)
- 【数据结构】之用堆实现优先队列
- 数据结构实现之最小索引优先队列
- uva 1203 - Argus (数据结构:优先队列+水题)
- 数据结构Java实现07----队列:顺序队列&顺序循环队列、链式队列、顺序优先队列
- 数据结构实现之最大索引优先队列
- HDOJ 1053 Huffman编码 自写优先队列的ADT 权当做练习数据结构