优先队列(堆)
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)。
相关文章推荐
- BroadcastReceiver 广播接收者
- pci_alloc_consistent 配合mmap
- android-topeka学习笔记(一)-----一些不知道的属性
- 门描述符
- Spring容器、Bean配置信息。Bean实现类及应用程序的关系
- No row with the given identifier exists 解决方法
- 我眼中的Window创建/添加/删除/更新过程
- 孤儿进程与僵尸进程[总结]
- 关于编程中的无穷大的一些事
- 架构设计:系统存储(3)——块存储方案(3)
- 对象的三大特性(封装、继承、多态)之------继承性 + 覆写
- 2002年分区联赛普级组之四 过河卒
- 第二十三条:不要在新代码中使用原生类型
- 偏执却管用的10条Java编程技巧
- python中*和**的用法
- JavaScript 冒泡排序和选择排序
- 面试集锦-常量,const, const 对指针的影响
- [POJ2761]Feed the dogs(静态区间第k小,主席树)
- CI框架的自动验证
- 机器学习笔记2-Supervised learning