湘潭大学 数据结构 课件 ppt Ch06 Priority Queues(Heaps)

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

§5 d-堆 ---- 所有的结点都有 d 个孩子
1 2 4 11 9 7 10 13 3 15 6 8 5 17 9
3-heap Question: d 是否越大越好?
Note: 1. DeleteMin 将需要进行 d 1 次比较来找出最小的孩子。因 此总的时间复杂度将会提高到 O(d logd N). 2.*2 或 /2 仅仅需要一次移位,但 *d 和 /d 不能通过移位实现。 3. 当优先队列太大不能完全装入主存的时候,d-堆是很有用的。 4. 在实践中4-堆可以胜过二叉堆。
PriorityQueue Initialize( int MaxElements ); void Insert( ElementType X, PriorityQueue H ); ElementType DeleteMin( PriorityQueue H ); ElementType FindMin( PriorityQueue H );
~ O( n ) ~ ( 1 ) ~ ( 1 )
二叉查找树:
§2 简单的实现
哦 , ! 呃哦 … 还不行吗 ? 你越来越聪明啦! 我想你是不是又有更好的想法了 ? 好 !, 对呀 好注意 其实 ……AVL 的许多操作 现在你开始懂 我了 我们总是从左子树删除 …. 像 AVL 树这种平衡二叉树并不一定是 可是要注意 ----插入是随机的, 插入和删除都只需要 对优先队列而言并不是必须的 . 而我们还必须保持树的平衡 …… 个坏主意,因为我们只需要增加常数的 O(log N) . 而删除不是。 而且, 运行时间。可是 … . 我们总是假定删除最大的元素 指针操作总带有某些潜在的危险
【定义】 “优先队列” (Priority Queue)是特殊的“队列”,从堆中 取出元素的顺序是依照元素的优先权(关键字)大小,而不是元素进入 队列的先后顺序。采用完全二叉树存储的优先队列 称为堆(Heap)。
§2 简单的实现
数组 :
Insertion — 元素插入在末尾 Deletion — 查找最大(或最小)关键字 从数组中删除需要移动元素 链表: Insertion —元素总是插入链表的头部 Deletion —查找最大(或最小)关键字 删去结点 有序数组: ~ (1) ~ (n) ~ O( n ) ~ (1) ~ (n) ~ ( 1 )
Percolate down
将堆 H 中位置 P 处的结点关键字增加 …… 将过度消耗CPU时间的进程降低优先级。
sys. admin.
§3 二叉堆
Delete ( P, H )
DecreaseKey(P, , H); DeleteMin(H)
sys. admin.
将堆 H 中位置 P 处的结点删除…… 当一个进 程由用户中止(非正常终止)时,它必须从优 先队列中除去。
2 3 4
B D A
5 10
F
6 BT 11 12
G C
0
71
A
2 B 9 I
3 C
4 D
5 E
6 F
8
E
9
13 14
7 G
8 H
15
10 11 12 13 J
H
I
J
§3 二叉堆
【引理】如果一棵具有 n 个结点的完全二叉树是顺序实现 的,那么对任意位置编号 i 的结点, 1 i n,有:
i 2 i f i 1 (1) i n de xof parent( i ) Non e i f i 1 i f 2i n 2i (2) i n de xof left _ child ( i ) Non e i f 2i n 2i 1 i f 2i 1 n (3) i n de xof right _ child ( i ) Non e i f 2i 1 n
Review
队列
先进先出 设想:
发送到打印机的文档放到队列中,如果希望先打印 重要的或短的文档? 操作系统调度程序使用队列,重要的或短的作业能 优先吗?
第六章 优先队列(堆)
—— 删除具有最高 / 最低优先级的元素
§1 ADT 模型
数据对象集: 一个有限的有序表,包含零个或多个元素。
数据操作集:
[2]
15 18
[4]
18
[5]
15 < 18
T (N) = O ( log N )
§3 二叉堆 ElementType DeleteMin( PriorityQueue H ) { 通过添加另一个 省略这个条件, int i, Child; 下滤 哨兵,能否去掉 会发生什么? ElementType MinElement, LastElement; 这个测试 ? if ( IsEmpty( H ) ) { Percolate down Error( "Priority queue is empty" ); return H->Elements[ 0 ]; } MinElement = H->Elements[ 1 ]; /* save the min element */ LastElement = H->Elements[ H->Size-- ]; /* take last and reset size */ for ( i = 1; i * 2 <= H->Size; i = Child ) { /* Find smaller child */ Child = i * 2; if (Child != H->Size && H->Elements[Child+1] < H->Elements[Child]) Child++; if ( LastElement > H->Elements[ Child ] ) /* Percolate one level */ H->Elements[ i ] = H->Elements[ Child ]; else break; /* find the proper position */ } H->Elements[ i ] = LastElement; return MinElement; }
那太。。。慢了! N successive Insertions ?
BuildHeap ( H )
将 N 个关键字以任意顺序放到一个空堆H中。
150, 80, 40, 30, 10, 70, 110, 100, 20, 90, 60, 50, 120, 140, 130 sys. admin.
150 10 150 80 10 20 150 20 30 10 80 60 70 50 40 110
§3 二叉堆
DeleteMin
算法梗概: 啊哈! 这很简单 -我们只要删除根结点 ... move 18 up to the root [1] 10 18 12 只能删除这个结点 并重新安排剩下的树结点, [3] 20 12 15 18 使之仍是最小树。 以保证树仍是完全二叉树 find the smaller child of 18 12 < 18
return; }
for ( i = ++H->Size; H->Elements[ i / 2 ] > X; i /= 2 ) H->Elements[ i ] = H->Elements[ i / 2 ];
H->Elements[ i ] = X; }
比swap快 T (N) = O ( log N )
[3]
6
3
[4]
20
83
5
一个最大堆
50
一个最小堆
3. 基本的堆操作:
§3 二叉堆
insertion
算法梗概:
[1]
[2]
10 9
[3]
12
20 17 10 9
15
[4]
18 20 21 17
[5] [6]
由于堆必须是完全二叉树, 这是唯一可能插入 新结点的位置。
情形 1 : new_item = 21 20 < 21 情形 2 : new_item = 17 20 > 17 10 < 17
2. 堆序性质:
§3 二叉堆
【定义】一棵最小树是树中任意结点的关键字不大于它 的孩子结点的关键字(如果有的话)。一个最小堆是 一棵完全二叉树,同时也是一棵最小树。
Biblioteka Baidu
Note: 类似地,我们可以声明一个最大堆,只要更改 堆序性质即可。
最大关键字 最小关键字
[1] [2] [4]
9
[3]
[1] [2]
10
4. 其他的堆操作:
§3 二叉堆
Note: 查找除最小元外的任何元素都需对整个堆进行线 性搜索。
DecreaseKey ( P, , H )
Percolate up
将堆 H 中位置 P 处的结点关键字减小 …… 因此我的程序可以以更高优先级运行 .
sys. admin.
IncreaseKey ( P, , H )
Insertion — 找到合适的位置 ~ O( n )或O(logn) 由于 Deletion的次数从不多余 移动元素并插入 ~ O( n ) Insertion 的次数,链表可能是 Deletion — 删去最后一个元素 ~ ( 1 )
有序链表:
更好的想法。
•Insertion —找到合适的位置 插入元素 Deletion — 删除首元素或最后元素
§3 二叉堆
【定理】对高度为 h ,包含 2h+1 1 个结点的满二叉树,结 点高度之和为 2h+1 1 (h + 1). T(N)=O(N)
§4 优先队列的应用
〖例1〗选择问题:已知一个有N个元素的表,给定一个整 数k,找到表中第k大的元素。
你能想到几种方法来解决这个问题? 它们各自的时间复杂度是多少?
T (N) = ?
100
150 20 30
90
60 80
50 70
120
140
130
PercolateDown (7) PercolateDown (6) PercolateDown (5) PercolateDown (4) PercolateDown (3) PercolateDown (2) PercolateDown (1)
§3 二叉堆
1. 结构性质: 【定义】一棵具有 n 个结点,高度为 h 的二叉树是完全二 叉树,当且仅当它的结点编号与高度为 h 的满二叉树结点 编号能一一对应。 一棵高度为 h 的完全二叉树结点数为 2h 至 2h+1 1 个。 h = log N
1
数组实现: BT [ n + 1 ] ( BT [ 0 ] 未使用)
情形 3 : new_item = 9
20 > 9
10 > 9
§3 二叉堆
/* H->Element[ 0 ] is a sentinel */ void Insert( ElementType X, PriorityQueue H ) { int i;
H->Element[ 0 ] 是一个 上滤 哨兵 ,即比堆中最小的值 if ( IsFull( H ) ) { Percolate up 还要小。 Error( "Priority queue is full" );
§3 二叉堆
PriorityQueue Initialize( int MaxElements ) { PriorityQueue H; if ( MaxElements < MinPQSize ) return Error( "Priority queue size is too small" ); H = malloc( sizeof ( struct HeapStruct ) ); if ( H ==NULL ) return FatalError( "Out of space!!!" ); /* Allocate the array plus one extra for sentinel */ H->Elements = malloc(( MaxElements + 1 ) * sizeof( ElementType )); if ( H->Elements == NULL ) return FatalError( "Out of space!!!" ); H->Capacity = MaxElements; H->Size = 0; H->Elements[ 0 ] = MinData; /* set the sentinel */ return H; }
相关文档
最新文档