优先队列:以集合为基础的抽象数据类型
· 支持运算:
1.Min(H):返回优先队列H中具有最小优先级的元素
2.Insert(x,H):将元素x插入优先队列
3.DeleteMin(H):删除并返回优先队列中具有最小优先级的元素
· 与字典的区别:字典插入运算仅当要插入的x与当前所有元素线性序值都不同时才插入。而优先队列中不同的元素可以有相同的优先级。
· 优先队列的实现
如果用字典实现有限队列:若用有序链表,查询最小元和删除最小元都为O(n),而插入需要O(n);若用二叉搜索树,最坏情况下插入删除O(n),平均情况O(logn)(若是AVL树最坏情况O(logn));若用无序链表,插入O(1),而删除需要O(n)。
二叉搜索树有一性质,中序列表是元素按照优先级从小到大排列,这一性质在优先队列中并不需要,因此可对二叉搜索树作适当修改,引入优先级树。
优先级树是满足下面的优先性质的二叉树:
1.树中每一结点存储一个元素
2.任一结点中存储的元素的优先级不大于其儿子结点中存储的元素的优先级
由此,优先级树的根节点中存储的元素具有最小优先级,从根到叶的任一路径上,结点中元素按优先级的非增序排列。
与二叉搜索树一样,优先级树可能退化成一个线性表。由于在优先级树中执行增删操作与树高有关,所以希望用平衡的优先级树来表示优先队列。当一棵优先级树是近似满二叉树时,称其为堆或偏序树。
用堆来实现优先队列可以获得较高的效率,增删都只要O(logn)的时间。
·堆的实现
(书上一堆优先级小于优先级的有点麻烦,下面全部按照优先级是数值大小的极小化堆来说(也即根元素最小,树中结点都比根大的堆))
删除:不是简单的删去树根,而是取出根节点,然后删去堆中最底层最右边的叶节点,用它取代树根,之后将这个元素不断地与比它小的儿子交换位置,直到它的两个儿子都不小于它或者它已经降到叶节点为止。
因为从树根到树叶的任一路径上最多只有1+logn个结点,所以删除运算只需O(logn)的时间。
插入:首先将新元素结点添加在堆的最底层,使它仍为一棵近似满二叉树。然后不断的与它的父亲比较,如果小于父亲则交换位置,直到新元素不小于父节点或者已经升到根节点为止。同理上升经过结点数不超过1+logn,所以插入在最坏情况下也只用O(logn)时间。
由于堆是一棵近似满二叉树数,所以可以方便的用数组实现堆。元素a[1] a[2] a[3] … a[n] 是堆中元素的按层序列表,即从根节点开始往下每层从左到右将元素列出的一串序列。根节点存放在a[1]中,a[i]的左儿子(若存在)存放在a[2i]中,右儿子在a[2i+1]中。换句话说当i>1时a[i]的父节点在a[i/2]中。
·可并优先队列——左偏树
用堆实现合并两优先队列的效率不高,下面讨论的左偏树结构不但能在O(logn)时间内支持同一队列中增删的基本运算,还能有效支持两不同优先队列的合并运算。
左偏树是一类特殊的优先级树。(下面讨论的都为极小化左偏树)
一棵优先级树是左偏高树的条件:在该树的每个内结点处,其左儿子结点的高大于等于右儿子节点的高;
一棵优先级树是左偏重树的条件:在该树的每个内结点处,其左儿子结点的重大于等于右儿子节点的重;
高度s(x) = min{ s(L},s(R) } +1;
重量w(x) = w(L) + w(R) + 1;
左偏树图解博客:http://www.cnblogs.com/yc_sunniwell/archive/2010/06/28/1766756.html
·优先队列应用实例 : 哈夫曼编码
//–作业题
11.2 girgirieye