堆与堆排序
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Adding an Entry
Begin at next available position for a leaf Follow path from this leaf toward root until find correct position for new entry As this is done
Fig. 27-4 An array representation of the steps in Fig. 27-3 … continued →
Adding an Entry
Fig. 27-4 (ctd.) An array representation of the steps in Fig. 27-3.
由于堆实质上是一个完全二叉树,那么我们可以 顺序存储一个堆。 顺序存储一个堆 下面以一个实例介绍建一个小根堆的过程。 例:有关键字为49,38,65,97,76,13,27, 例: 49的一组记录,将其按关键字调整为一个小根堆。
49 38 97 49 76 13 65 27
13 49 38 97 49 97 49 76 13 65 27 13 49 65
时间复杂度分析
该方法创建堆的时间复杂度为O( n ) 证明过程请看教材341页
7.5.2 堆和堆排序
一、堆和堆排序的概念 二、堆的调整 三、建堆 ☞ 四、堆排序
Heapsort
Fig. 27-9 A trace of heapsort (a – c)
Heapsort
Fig. 27-9 A trace of heapsort (d – f)
4 15 16 25 7 5 12 11 8 9
6 23 27 20
Example (end)
10 4 15 16 25 7 5 12 11 8 9 27 6 23 20
4 5 15 16 25 10 7 12 11 8 9 27 6 23 20
Analysis
We visualize the worst-case time of a downheap with a proxy path that goes first right and then repeatedly goes left until the bottom of the heap (this path may differ from the actual downheap path) Since each node is traversed by at most two proxy paths, the total number of nodes of the proxy paths is O(n) Thus, bottom-up heap construction runs in O(n) time Bottom-up heap construction is faster than n successive insertions and speeds up the first phase of heap-sort
堆与堆排序
软件学院 王建文
7.5.2 堆和堆排序
☞ 一、堆和堆排序的概念 二、堆的调整 三、建堆 四、堆排序
堆的定义: 个元素的序列{a 若n个元素的序列 1 a2 … an} 满足 个元素的序列 ai ≤ a2i ai ≤ a2i+1 或 ai ≥ a2i ai ≥ a2i+1
则分别称该序列{a 大根堆。 则分别称该序列 1 a2 … an}为小根堆 和大根堆。 为 从堆的定义可以看出, 从堆的定义可以看出,堆实质是满足如下性质的完 全二叉树: 全二叉树: 二叉树中任一非叶子结点均小于(大于) 二叉树中任一非叶子结点均小于(大于)它的孩子结点
Adding an Entry----代码见课本203
Algorithm for adding new entry to a heap
Algorithm add(newEntry) if (the array heap is full) Double the size of the array newIndex = index of next available array location parentIndex = newIndex/2 // index of parent of available location while (newEntry > heap[parentIndex]) { heap[newIndex] = heap[parentIndex] // move parent to available location // update indices newIndex = parentIndex parentIndex = newIndex/2 } // end while
实现堆排序需解决两个问题: 实现堆排序需解决两个问题: 1、如何由一个无序序列建成一个堆? 2、如何在输出堆顶元素后,调整剩余元素为一个新 的堆?
下面先讨论第二个问题: 下面先讨论第二个问题:
7.5.2 堆和堆排序
一、堆和堆排序的概念 ☞ 二、堆的调整 三、建堆 四、堆排序
如何在输出堆顶元素后,调整剩余元素为一个新 的堆? 解决方法: 输出堆顶元素之后, 输出堆顶元素之后,以堆中最后一个元素替代 然后将根结点值与左、 之;然后将根结点值与左、右子树的根结点值进行比 并与其中小者进行交换;重复上述操作, 较,并与其中小者进行交换;重复上述操作,直至叶 子结点,将得到新的堆, 子结点,将得到新的堆,称这个从堆顶至叶子的调整 过程为“筛选” 过程为“筛选”
首先, 调整从第n/2 n/2个元素开始 首先, 调整从第n/2个元素开始 将以该元素为根的二叉树调整为堆 然后,将以序号为n/2 n/2- 然后,将以序号为n/2-1的结点 为根的二叉树调整为堆; 为根的二叉树调整为堆; 27 49 再将以序号为n/2 n/2- 再将以序号为n/2-2的结点为根 的二叉树调整为堆; 的二叉树调整为堆; 再将以序号为n/2 n/2- 再将以序号为n/2-3的结点为根 的二叉树调整为堆; 的二叉树调整为堆;
{ int j ; j = 2*i ; while ( j <= m)
//若j<=m,R[2*i]是R[i]的左孩子 若 , 是 的左孩子
{ if ( j<m &&R[j].key> R[j+1].key)
比较左右孩子的大小, 为较小的孩子的下标 j ++ ; // 比较左右孩子的大小,使j为较小的孩子的下标
你能画出删除堆顶元素时相应数组的变化吗? 你能画出删除堆顶元素时相应数组的变化吗? 删除元素代码见课本204 删除元素代码见课本
7.5.2 堆和堆排序
一、堆和堆排序的概念 二、堆的调整 ☞ 三、建堆 四、堆排序
第一种方法:
把一个数组看成两部分,左边是堆,右边是还 没加入堆的元素,步骤如下: 1、数组里的第一个元素自然地是一个堆 2、然后从第二个元素开始,一个个地加入左 边的堆,当然,每加入一个元素就破坏了左边 元素堆的性质,得重新把它调整为堆
堆排序 若在输出堆顶的最小值(最大值) 若在输出堆顶的最小值(最大值)后,使得剩余 n-1个元素的序列重又建成一个堆,则得到n个元素 个元素的序列重又建成一个堆,则得到 个元素 个元素的序列重又建成一个堆 的次小值(次大值) 如此反复, 的次小值(次大值)……如此反复,便能得到一个 如此反复 有序序列,这个过程称之为堆排序 堆排序。 有序序列,这个过程称之为堆排序。
自底向上地创建堆
16
15
4
12
6
7
23
20
25 16 15 4
5 12 6
11 7 23
27 20
Example (contd.)
25 16 15 4
5 12 6
11 9 23
27 20
15 16 25 5
4 12 11
6 9 27
23 20
Example (contd.)
7 15 16 25 5 4 12 11 6 9 27 8 23 20
Heapsort
Fig. 27-9 A trace of heapsort (g – i)
Heapsort
显然: 单结点的二叉树是堆; 单结点的二叉树是堆;在完全二叉树中所有以叶子 结点(序号i 结点(序号 > n/2)为根的子树是堆。 )为根的子树是堆。 这样,我们只需依次将以序号为 , - , 这样,我们只需依次将以序号为n/2,n/2-1,……, 1的结点为根的子树均调整为堆即可。 的结点为根的子树均调整为堆即可。 的结点为根的子树均调整为堆即可 即:对应由n个元素组成的无序序列,“筛选” 即:对应由n个元素组成的无序序列,“筛选”只需 从第n/2个元素开始。 从第n/2个元素开始。
6 7 8
0
1
2
3
4
5
49 65 13 27 97 13 38 27 49 76 65 49 49 49 13 97
筛选过程的算法描述为: sift (rectype R[ ] , int i , int m )
// 在数组 中将下标从 到m的元素序列调整为堆,即将以 在数组R中将下标从 中将下标从i到 的元素序列调整为堆 的元素序列调整为堆, R[i]为根的子树调整为堆;初次调整的是以序号 为根的子树调整为堆; 为根的子树调整为堆 初次调整的是以序号m/2的结点为根的 的结点为根的 子树; 子树;
删除元素
Fig. 27-5 The steps to remove the entry in the root of the maxheap of Fig. 27-3d
Removing the Root
Fig. 27-6 The steps that transform a semiheap into a heap without swaps.
创建堆
时间复杂度
该方法创建堆的时间复杂度为O (n log n)
第二种方法:自底向上创建堆
可以看出: 对一个无序序列反复“筛选”就可以得到一个堆 对一个无序序列反复“筛选”就可以得到一个堆 反复 从一个无序序列建堆的过程就是一个反复 筛选” 建堆的过程就是一个反复“ 即:从一个无序序列建堆的过程就是一个反复“筛选” 的过程。 的过程。 那么:怎样判断一个序列是一个堆?或者说,建堆操 作从哪儿着手?
if ( R[i].key > R[j].key ) { R[i] <-> R[j] ; // 将较小的孩子与根交换 - i = j ; j = 2*i ; // 上述交换可能使以该孩子结点为根的
子树不再为堆, 子树不再为堆,则需重新调整
} else break ; } }
将初始无序的R[1]到R[n]建成一个小根堆,可用以 到 建成一个小根堆, 将初始无序的 建成一个小根堆 下语句实现: 下语句实现: for ( i = n/2 ; i >= 1 ; i - - ) sift ( R , i , n ) ;
Move entries from parent to child Makes room for new entry
Adding an Entry
Fig. 27-3 A revision of steps shown in Fig. 27-2 to avoid swaps.
Adding an Entry
97 13 27 38 49 97 76 65 97 27 49 49 97
பைடு நூலகம்
输出根并以最后一个元素代 替之; 替之; 比较其左右孩子值的大小, 比较其左右孩子值的大小, 并与其中较小者交换; 并与其中较小者交换; 小根堆
13
堆调整与数组变化的关系
加入元素时向上调整 删除元素时向下调整
加入元素
Fig. 27-2 The steps in adding 85 to the maxheap of Figure 27-1a
例: 下面序列为堆,对应的完全二叉树分别为: 98 14 77 48
98
48
35
62 55
14
35 48 35 77
14
35 62
55 98
77
35
62
35
62
55
14
35
77
55
98
35
48
堆的应用------优先级队列
服务排队------见课本 见课本200, 例5.1 服务排队 见课本 堆排序