优先队列及其应用
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1 3 5 3
1 5
4
5
7
8
2
5
7
8
6
2 (1)将新节点插到最后 1 2 5
6
4 (2)把新节点和父亲进行交换
3
5
7Baidu Nhomakorabea
8
6
4 (3)继续交换,直到重新满足堆的性质
插入 (实际上是不断向上调整的过程)
• • • • • • • • • • • • • PROC up (k:longint); {把第k个结点上调} begin while k>1 do begin i:=k div 2; {i是k的父亲} if st[i]>st[k] then begin swap(i,k); k:=i; {交换结点i和k} end else exit; end; end;
子节点的值。
9
87
17
65
78
53
23
45
78
87
45
65
9
31
53
9 17 65
31
23
ki≤k2i且ki≤k2i+1
45 78 87 53 31 87
17
78 53
23
45
ki≥k2i且ki≥k2i+1
65 9 31 17 23
最小堆(MinHeap)
最大堆(MaxHeap)
• 最小(大)堆:位于堆顶(即完全二叉树的根节点位 置)的节点的值是整个序列中最小(大)的。
一个基本问题
• • • • • 写一种数据结构,完成以下3种操作: (操作的总次数不超过100000) 1、插入一个数 2、询问最小值 3、删除最小值
• 要求是这3种操作都要快。。。
输入输出
输入 每行一次操作,有如下三种: 1 x:表示插入X这个数 2 :表示询问当前最小值 3: 表示删除最小值 输出 对于每个询问最小值操作,输出一行,每 行仅一个数,表示当前的最小值。
斜堆合并示例(非递归实现)
斜堆合并示例(递归实现)
斜堆的摊还分析
• 证明斜堆合并的摊还时间为O(logN) • 定义:一个节点p,若其右子树的后裔数至少是p的后裔 数的一般,则称p是重节点,否则称为轻节点 • 位势的选取:右路径上重节点的数目
斜堆的摊还分析
证明: 令H1和H2为两个斜堆,节点数为N1和N2,右路径上轻重节点数目 分别为l1和h1、 l2和h2 若合并代价定义为右路径上节点总数,则代价为l1+h1+l2+h2 合并操作的重要特性:右路径上的重节点肯定变为轻节点;而轻节 点可能不变,也可能变为重节点。 考虑最坏情况,当然是所有轻节点均变为重节点 则位势(重节点数)的变化为l1+l2-h1-h2 平均摊还时间=代价+位势变化=2(l1+l2) 现在只需证明l1+l2=O(logN) 而l1和l2是原右路径上的轻节点数目,而轻节点左子树重、右子树 轻,因此l1+l2至多为logN1+logN2,即O(logN) 而初始位势为0,始终非负,命题得证。
插入操作实例1
A B
插入操作实例2
A B
插入操作实例3
A B
插入操作实例4
A B
初始化最大HBLT
• n个元素依次插入空HBLT:O(nlogn) • 线性时间算法
– 构造n个单元素的HBLTFIFO队列 – 删除队列前两个HBLT合并,加入队尾 – 重复,直至只剩一个HBLT
初始化实例
定理
• 定理: 令x为一个HBLT的内部节点,则
1) 以x为根的子树的节点数目至少为2s(x)-1。 2) 若子树x有m个节点,s(x)最多为log2(m+1)。 3) 通过最右路径(即,此路径是从x开始沿右孩 子移动)从x到达外部节点的路径长度为s(x)
证明
由s(x) 定义从x向下的s(x)-1层内没有外部节点 (否则s(x) 将更小) 子树第一层只有x,下一层有两个,..., 第s (x)-1 层有个2s (x) - 1,节点数目至少为
引例1:机器服务收费
假设我们对机器服务进行收费。 每个用户每次使用机器所付费用都是相同的,但每个用 户所需要服务时间都不同。 为获得最大利润,假设只要有用户机器就不会空闲,我 们可以把等待使用该机器的用户组织成一个最小优先队 列,优先权即为用户所需服务时间。当一个新的用户需 要使用机器时,将他/她的请求加入优先队列。一旦机器 可用,则为需要最少服务时间(即具有最高优先权)的 用户提供服务。 如果每个用户所需时间相同,但用户愿意支付的费用不 同,则可以用支付费用作为优先权,一旦机器可用,所 交费用最多的用户可最先得到服务,这时就要选择最大 优先队列。
样例
输入: 9 ----1 20 2 1 30 1 10 2 3 2 3 2
9次操作 输出: 20 10 20 30
用线性表作为数据结构
• 无序表:
– 插入操作 – 询问最小值 – 删除最小值 O(1) O(n) O(n) O(n) O(1) O(1)
• 有序表:
– 插入操作 – 询问最小值 – 删除最小值
n n n i O ( 2 * 3 * ) O (n i ) O ( n ) 2 4 8 2
斜堆(skew heap)
• 斜堆可递归的定义如下: ● 只有一个元素的堆是斜堆。 ● 两个斜堆通过斜堆的合并操作,得到的结果 仍是斜堆 • 与左高树类似,但无“左高”这一限制 • 各种操作与左高树类似,也是以合并为基础 • 但递归合并过程中,左右孩子的交换不是以达到“ 左高”为目的,而是无条件的,只有最后(右)节 点例外(递归停止)
优先队列的线性表实现
无序顺序表 • 插入在表的末尾,Θ(1) • 删除时先查找优先权最大的元素,Θ(n)。
无序链表 • 插入在链头,Θ(1) • 删除时先查找优先权最大的元素,Θ(n)。 有序线性表 • 插入时间,Θ(n) • 删除时间,Θ(1)。 • 优先队列的另一种实现方式——堆(Heap)。
斜堆的合并操作
• 我们可以用左高树的合并算法实现两个斜堆的合并。除此之 外,还有一种非递归的算法。 • 分割每个堆。方法是从根节点开始,右子树与根节点分离, 然后右子树以同样的方式分割。 • 最后得到一个树的集合,集合中的树的特点是:其根节点只 有左子树或者没有子树。 • 对集合中的树,按照根节点的值从小到大排序。 • 从右到左,不断地合并最后两个子树,直到只剩下一棵树。 • 合并方法是: • 如果倒数第二棵树有左子树,那么把左子树变为右子树。 • 把最后一棵树作为倒数第二棵树的左子树。
s ( x ) 1 i 0 i s( x) 2 2 1
由1) 可得2) 根据s 的定义,及HBLT一个节点的左孩子的s 值 总是大于等于其右孩子的s 值,可以推得3)成立 。
最大(小)HBLT
• 定义[最大(小)HBLT]: 即同时又是最大(小)树的HBLT
重量
• w(x):以x为根的子树的内部节点数目
堆的构造就是不断插入到堆的过程
6 2 3 5 1 分别插入权为6,2,3,5,1的元素 2 2
6 (1) 6
6 (2) (3) 1
3
2
5
3
2
3
6 (4)
6
5
(5)
堆的插入.删除
PROC add(x:longint); {添加一个值为x的元素} begin inc(n); st[n]:=x; up(n) end; PROC del(x:longint); {删除一个值为x的元素} begin a[n]:=a[x]; down(x) end;
在堆中插入元素x
• 首先将元素x放到堆中的最后一个位置(即最 底层最右边的位置),然后不断地把x往上调 整,直到x调不动为止(即大于它现在的父亲, 或者x处于根结点)。
定义一个堆: Var st:array[1..maxn] of longint; //存储堆 n:longint; //堆中元素个数
– 外部节点:w(x)=0 – 内部节点:w(x)=w(L)+w(R)+1
重量优先左高树
• 定义[重量优先左高树]: 当且仅当一棵二叉树的任一内部节点, 其左孩子的w值大于等于右孩子的w值,该 二叉树为重量优先左高树(weight-biased leftist tree, WBLT) [最大(小)WBLT]: 即同时又是最大(小)树的WBLT
希望构造具有五个元素:7 , 1 , 9 , 11 , 2 的一棵最大H B LT。如下图: ① 7,1合并成为a) ② 9,11合并成为b) ③ 2和 a)合并成为c) ④ 最后b)和c)合并成为d)
复杂性分析
• 初始化的复杂性
– n是2的幂:合并n/2对一个元素的HBLT合并 n/4对二个元素的HBLT... – 合并两棵2i个元素的HBLT:O(i+1) – 总时间复杂性
堆(Heap)
堆的定义
设有n个数据元素的值为(k1,k2,…,kn),如果它们满足
以下的关系:ki≤k2i且ki≤k2i+1(或ki≥k2i且ki≥k2i+1)(i=1,…,
n/2),则称之为堆(Heap)。 如果将此数据元素序列用一维数组存储,并将此数组对 应一棵完全二叉树,则堆的含义可以理解为:在完全二叉 树中任何非终端节点的值均不大于(或小于)其左、右孩
在堆中删除任意一个元素
• 这里说指的删除任意一个元素,是指在当 前堆中位置为w的元素。过程如下:首先把 位置w的元素和最后一个位置的元素交换, 然后删去最后一个位置,这样w上的元素就 被删除了。接着把位置w上的新元素不断下 调,直到满足堆的性质。
1 2 5 4
1 5
3
5
7
8
3
5
7
8
6
4
6
2
(1)当前要删除的节点是根节点的左儿子 1
引例2 工厂仿真
对其事件队列所执行的操作 1) 查找最小完成时间的机器 2) 改变机器的完成时间 构造构造一个最小优先队列,队列中的元素即为机 器,元素的优先权为该机器的完成时间。 当机器可用,选择优先级最大的任务执行,任务队 列操作: 1) 新任务到达,插入最大优先队列 2) 一旦机器可以开始运行一个新任务,将具有最大 优先权的任务从该机器的队列中删除,并开始执 行它。
HBLT和WBLT的操作
• 查找、插入、删除与堆一样 • 初始化也可在线性时间内完成 • 两个优先队列合并:对数时间,这是堆达不 到的
最大HBLT的插入、删除操作
• 插入操作可借助合并操作
– 元素x插入到名为H的最大HBLT
• 构造只有一个元素x的最大HBLT H’ • H’与H合并
• 删除操作也可借助合并操作
优先队列及其应用
雅礼 朱全民
优先队列的基本概念
队列:FIFO(按元素进入队列的次序); 优先队列(Priority Queue):出队列的顺序由元 素的优先级决定,如: • 医院中的急诊处理; • 操作系统中使用优先队列进行作业调度; • 事件驱动模拟处理。
优先队列的基本操作
ADT MaxPriorityQueue { 实例 有限的元素集合,每个元素都有一个优先权操作 Create( ):创建一个空的优先队列 Size( ):返回队列中的元素数目 Max( ):返回具有最大优先权的元素 Insert(x):将x插入队列 DeleteMax(x):从队列中给删除具有最大优先权的元素, 并将该元素返回至x }
– 删除根节点
• 两个子树L、R均为最大HBLT • 合并L、R
最大HBLT的合并操作
• 遍历右路径——O(logn) • 递归,合并A、B
– 若一个为空,则另一个为合并结果 – 若都不空
• • • • 比较两个根节点,较大者为新的根 假定A较大,左子树为L,右子树为R 递归方法将R与B合并为C 最终合并结果:A的根为根;L、C的s值较大者为 左子树,另一个为右子树
(2)将根节点的左儿子和最后一个节点交换
3
5
4
5
7
8
6
(3)将新的节点不断下调,直到满足堆的性质
删除 (实际上是不断向下调整的过程)
PROC down(k:longint);{把第k个结点往下调} begin while k+k<=n do begin i:=min{ 2k,2k+1}; {如果2k+1不存在直接返回k+k否则返回2个中间的值较小的 元素} if st[i]<st[k] then begin swap(i,k); k:=i; end else exit end; end;
扩充二叉树
内部节点 外部节点
函数s(x)的定义
s(x):x到其子树外部节点 路径长度最短值
外部节点:s(x)=0
内部节点: s(x)=min{s(L), s(R)}+1 L、R——x的左右孩子
左高树定义
• 定义[高度优先左高树]: 当且仅当一棵二叉树的任一内部节点, 其左孩子的s 值大于等于右孩子的s 值, 该二叉树为高度优先左高树(heightbiased leftist tree, HBLT)
d-堆
• 多叉堆 • 优先队列无法全部装入内存 • 在实际应用中,4-堆可胜过二叉堆
左高树(或左偏树)
高度与宽度优先的最大及最小左高树 • 堆——隐式(implicit)数据结构
– 没有明确的指针,没有存储结构信息 – 空间利用率最高 – 不适用所有优先队列应用——合并长度不等的 优先队列
• 左高树(leftist tree)适合此类应用