您的位置:首页 > 其它

优先队列(堆)

2016-09-03 16:17 399 查看

优先队列(priority model)模型

  insert:等价enqueue(入队)操作

  deleteMin:它的工作是找出、返回并删除优先队列中最小的元素,等价dequeue(出队)操作

优先队列基本模型:


  

优先队列可以用外部排序。在贪婪算法(greedy algorithm)的实现方面优先队列也是很重要的,该算法通过反复求出最小元来进行操作。

一些简单的实现

  1)使用一个简单链表在表头以O(1)执行插入操作,并变量该链表以删除最小元,这需要O(N)时间。

  2)始终让链表保持排序状态,这使得插入代价高昂(O(N))而deleteMin花费低廉(O(1))。方法1比方法2好。

  3)使用二叉查找树,它对这两种操作(插入、删除)的平均运行时间都是O(logN)。尽管插入是随机的,而删除则不是,但这个结论还是成立的。

二叉堆(binary heap)

  就是平时所说的堆(heap)。性质:结构性和堆序性。堆的操作必须到堆的所有性质都被满足时才能终止。

结构性质

  堆是一颗被完全填满的二叉树,有可能的例外是在底层,底层上的元素从左到右填入。这样的树称为完全二叉树(complete binary tree)。



一颗高为h的完全二叉树有2h到2h+1-1个节点。这意味着完全二叉树的高是小于等于logN的整数值,显然它是O(logN)。

完全二叉树的数组实现:



一个堆结构将由一个(Comparable对象的)数组和一个代表当前堆大小的整数组成。类架构如下:

public class BinaryHeap<AnyType extends Comparable<? super AnyType>> {

public BinaryHeap(){}

public BinaryHeap(int capacity){}

public BinaryHeap(AnyType[] items){}

public BinaryHeap(AnyType x){}

public AnyType findmin(){}

public AnyType deleteMin(){}

public boolean isEmpty(){}

public void makeEmpty(){}

private static final int DEFAULT_CAPACITY = 10;

private int currentSize;  //堆中元素数量

private AnyType[] array;  //堆数组

private void percolateDown(int hole){}

private void buildHeap(){}

private void enlargeArray(int newSize){}

}


堆序性质(heap-order property)

  让操作快速执行的性质是堆序性质。在一个堆中,对于每一个节点X,X的父亲中的关键字小于(或等于)X中的关键字,根节点除外(它没有父亲)。

基本的堆操作

insert(插入)

  为将一个元素X插入到堆中,我们在下一个可用位置创建一个空穴,否则该堆将不是完全树。如果X可以放在该空穴中而并不破坏堆的序,那么插入完成。否则,我们把空穴的父节点上的元素移入该空穴中,这样,空穴就朝着根的方向上冒一步。继续该过程直到X能被放入空穴中为止。这种策略叫做上滤(precolate up)。

插入到一个二叉堆的过程:

/**
* Insert into the priority queue,maintaining heap order.
* Duplicates are allowed
* @param x the item to insert
*/
public void insert(AnyType x){
if(currentSize==array.length-1){
enlargeArray(array.length*2+1);
}

//Percolate up
int hole = ++currentSize;
for(;hole>1 && x.compareTo(array[hole/2])<0;hole/=2){
array[hole] = array[hole/2];
}
array[hole] = x;
}


deleteMin(删除最小元)

  当删除一个最小元时,要在根节点建立一个空穴。由于现在堆少了一个元素,因此堆中最后一个元素X必须移动到该堆的某个地方。如果X可以被放到空穴中,那么deleteMin完成。不过这一般不太可能,因此我们将空穴的两个儿子中较小者移入空穴,这样就把空穴向下推了一层。重复该步骤直到X可以被放入空穴中。因此,我们的做法是将X置入沿着从根开始包含最小儿子的一条路径上一个正确的位置。这种策略叫做下滤(percolate down)。

在二叉堆中执行deleteMin的方法:

/**
* Remove the smallest item from the priority queue
* @return the smallest item,or throw UnderflowException,if empty
*/
public AnyType deleteMin(){
if(isEmpty()){
throw new UnderflowException();
}

AnyType minItem = findMin();
array[1] = array[currentSize--];
percolateDown(1);
return minItem;
}

/**
* Internal method to percolate down in the heap
* @param hole the index at which the perolate begins
*/
private void percolateDown(itn hole){
int child;
AnyType tmp = array[hole];
for(;hole*2<=currentSize;hole=child){
child = hole*2;
if(child!=currentSize&&array[child+1].compareTo(array[child])<0){
child++;
}
if(array[child].compareTo(tmp)<0){
array[hole] = array[child];
}else{
break;
}

}
array[hole] =tmp;
}


decreaseKey(降低关键字的值)

  decreaseKey(p,)操作降低在位置p处的项的值,降值的幅度为正的量。由于这可能破坏堆序性质,因此必须通过上滤对堆进行调整。

increaseKey(增加关键字的值)

  increateKey(p,)操作增加在位置p处的项的值,增值的幅度为正的量。这可以用下滤来完成。

delete(删除)

  delete(p)操作删除堆中位置p上的节点。该操作通过首先执行decreaseKey(p,无穷)然后再执行deleteMin()来完成。当一个进程被用户中止(而不是正常终止)时,它必须从优先队列中除去。

buildHeap(构建堆)

  

/**
* Construct the binary heap given an array of items
*/
public BinaryHeap(AnyType[] items){
currentSize = items.length;
array = (AnyType[])new Comparable[(currentSize+2)*11/10];
int i = 1;
for(AnyType item:items){
array[i++] = item;
}
buildHeap();
}

/**
* Establish heap order property from an arbitrary
* arrangment of items. Runs in linear time
*/
private void buildHeap(){
for(int i=currentSize/2;i>0;i--){
percolateDown(i);
}
}


包含2h+1 - 1 个节点,高为h的理想二叉树(perfect binary tree)的节点的高度的和为2h+1 - 1 - (h+1)。

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: