您的位置:首页 > 理论基础 > 数据结构算法

数据结构:优先队列

2017-10-12 17:01 183 查看
一般我们前面介绍的队列,队列的一个特性是先进先出。但是在作业调度的过程中我们总是希望很短的作业可以优先处理,这样我们就不用一味的等待短的作业而花费很长的时间去处理。但是同时有些短的但是很重要的作业也应该享有优先权。

优先队列至少允许以下两种操作,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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: