第9章 内排序-2
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
36 85 12
比较
47
一旦已调整为堆,则输出堆顶元素,重复将剩余 元素重新调整为一个新堆。
24 36 30 47 91 53 36 85 12 53 30
交换堆顶元素与序列末端 的元素
85 12
47
91
24
输出堆顶元素后,将剩余元素重新调整为一个新堆
53 36
85 47 91
30
24
调整成堆
(f)
53
91
85
30
53
91
当以下标1为根的完全二叉树为堆时,初始堆已建立 也可以从空堆开始建初始堆
10.4 堆排序
1964年弗洛伊德(Floyd)提出了筛选法建立初始堆, 具体方法是: 将待排序的关键字分放到一棵完全二叉树的各个结 点中(此时完全二叉树并不一定具备堆的特性), 显然,所有i≥[n/2]的结点Ki都没有子结点,以这 样的Ki为根的子树已经是堆,因此初始建堆可从完 全二叉树的第i个结点Ki开始(i=[n/2])。通过调整, 逐步使以K[n/2],K[n/2]-1,K[n/2]-2,…为根的子树满足 堆的定义,直至进行到以K1为根的树排成堆为止。
在n个关键字中选出最小者,需要n-1次比较,继续 在剩余的n-1个元素中选出次小者需要n-2次比较, 依此类推。 – 空间复杂度:O(1) • 只需要 1 个辅助单元进行交换 – 适用情况
• •
•
元素数目少的情况 无需完全排序的情况,比如,选出第i小的元素
9.4 选择排序
2. 树形选择排序(Tree Selection Sort) – 又称锦标赛排序(Tournament Sort):首先对n个记录的 关键字两两进行比较,然后在n/2个较小者之间再进行 两两比较,如此重复,直至选出最小关键字的记录。 整个过程可用一个含有n个叶结点的二叉树表示。 – 例如
堆(完全二叉树)
12
96 83
38 11 9
36
24 47
27
91
85
30
53
(a) 大顶堆(max heap)
k i k 2i k i k 2i 1
(b) 小顶堆(min heap)
k i k 2i k i k 2i 1
3. 堆排序(Heap Sort)
– 对一组待排序记录的关键字,首先把它们按堆的定 义建成小(大)顶堆,然后输出堆顶的最小(大)关键 字所代表的记录,再对剩余的关键字建堆,以便得 到次小(大)的关键字,如此反复进行,直到全部关 键字排成有序序列为止。
重复上述过程,将堆顶元素与堆中最后一个元素交换且调整, 又得到了有n-2个元素的新堆。为节省存贮开销,可以把输出 的最小(大)关键字放在Kn的位置上,把第二次输出的次小(大) 关键字存放在 Kn-1 的位置上 ……,直至最大 (小)关键字放在 K1 的位置上。
建初始堆
47 36 91 85 85 91 12 30 53
34 12 49 28 31 52 51 49*
12
12
28
31
31 12
49*
2. 树形选择排序(Tree Selection Sort)
– 又称锦标赛排序(Tournament Sort):首先对n个记录的 关键字两两进行比较,然后在n/2个较小者之间再进行 两两比较,如此重复,直至选出最小关键字的记录。 – 选出最小记录后,将树中的该最小记录修改为∞,然后 从该叶子结点所在子树开始,修改到达树根的路径上的 结点
30 36 85 47 53
wenku.baidu.com
12
91
24
12
9.4 堆排序过程示例
输出堆顶元素后,将剩余元素重新调整为一个新堆
调整堆元素(筛选 91 )
对于给出的关键字序列,经初始建堆后便得到小(大)顶堆, 反复将堆顶元素与序列末 从而得到最小 ( 大 ) 关键字。 36 53 端的元素的交换,并重新
调整成堆。 在输出堆顶元素之后,用堆中最后一个元素替代 30 47 85 24 之。此时由于以 K2和K3为根的子树仍具有堆的特性, 91 因此只需自上而下进行调整即可。
9.4 堆排序
在对Ki为根的子树建堆时,其子树已经为堆, 要使得以Ki为根的完全二叉树为堆,则可能要调 整父、子结点的位置,如此下一层已建成堆的 子树可能不再满足堆的定义,则需继续进行调 整,如此一次次递推下去,最多可能一直延伸
到树叶。这种方法就像过筛子一样,把最小(大)
的关键字一层一层地筛选出来,最后输出堆顶 的最小(大)关键字。
12
调整过程为:首先令K1的两个子树根进行比较,令其中较 85 53 小(大)者与K1相比较,将最小(大)元素交换至 K1,使得 K1、K2 和K3成为堆。由于交换后破坏了子树的堆性质,则需再次进行 30 36 与上述过程类似的调整,直至进行到最下层的叶结点为止。调 47 24 整后即得到一个有n-1个元素的新堆,从而得到次小关键字。 12
34 12 ∞ 49 28 31 52 51 49* 34 28 28 28 31 31 49*
2. 树形选择排序(Tree Selection Sort)
– 又称锦标赛排序(Tournament Sort):首先对n个记录的关键字两两进行 比较,然后在n/2个较小者之间再进行两两比较,如此重复,直至选出 最小关键字的记录。 – 选出最小记录后,将树中的该最小记录修改为∞,然后从该叶子结点 所在子树开始修改到达树根的路径上的结点 – 以后每选出一个小元素,都只需进行(logn)次比较
24 36
47
12 24
30 53
建初始堆
从最后一个具有叶子的结点(编号[n/2])开始建 子堆,依次考查结点[n/2]-1,[n/2]-2,...,1等 是否为堆,若否则调整为堆
47 36 91 12 30 53 36 47 53 12
24 91
85
30
24
85
(a)
(b)
建初始堆
从最后一个具有叶子的结点(编号[n/2])开始建 子堆,依次考查结点[n/2]-1,[n/2]-2,...,1等 是否为堆,若否则调整为堆
47 36 24 12 12 53 91
(C) (d)
47 24 36 30 53
85
30
85
91
建初始堆
从最后一个具有叶子的结点(编号[n/2])开始建 子堆,依次考查结点[n/2]-1,[n/2]-2,...,1等 是否为堆,若否则调整为堆
12 47 85 36
(e)
12 24 30 36 24 47
rc = H.r[s];
for ( j=2*s; j<=m; j*=2) {//沿key较大的孩子结点向下筛选 if ( j<m &<(H.r[j].key, H.r[j+l].key) ++ j; //j为key较大的记录的下标 if (! LT(rc. key, H.r[ j].key) ) break; H.r[s] = H.r[j]; s = j; } H.r[s] = rc;
输出堆顶元素后,将剩余元素重新调整为一个新堆
调整堆元素(筛选)
对于给出的关键字序列,经初始建堆后便得到小 ( 大 ) 顶堆,从而得到最小 (大)关键字。 在输出堆顶元素之后,用堆中最后一个元素替代之。此时由于以K2和K3为根的 子树仍具有堆的特性,因此只需自上而下进行调整即可。 首先令 K1 将的两个子树根进行比较,令其中较小 ( 大 ) 者与 K1 相比较,将最小 如此,我们已经可以在初始情况为堆的情况下完成排序,那么, (大)元素交换至K1,使得K1、K2和K3成为堆。由于交换后破坏了右子树的堆,则需 再次进行与上述类似的调整,直至进行到最下层的叶结点。调整后即得到一个有n如何建立起初始堆呢? 1个元素的新堆,从而得到次小关键字。
9.4 选择排序
1. 简单选择排序
– 简单选择排序的基本思想是:第一趟在n个记 录中选取最小记录作为有序序列的第一个记录, 第二趟在n-1个记录中选取最小记录作为有序 序列的第二个记录,第i趟在n-i+1个记录中选 取最小的记录作为有序序列多中的第i个记录。
9.4 简单选择排序过程示例
0
1 34 12 12 12 12 12 12 12 2 12 34 28 28 28 28 28 28 3 49 49 49 31 31 31 31 31 4 28 28 34 34 34 34 34 34 5 31 31 31 49 49 49 49 49 6 52 52 52 52 52 52 7 51 51 51 51 51 51 8 49* 初始关键字序列 49* 49* 49* 49* 49* 52 52
实现堆排序需要解决两个问题: (1) 如何建堆? (2) 输出堆顶元素后,如何将剩余元素重新调整为一 个新堆?
9.4 堆排序过程示例
下面是一个小顶堆,输出堆顶元素后,将剩余元素 重新调整为一个新堆的方法是:从树根开始,若以 某结点为根的子树不是堆,则将其孩子中的较小者 与之交换,即将非堆的子树推向叶子方向
i=1 i=2 i=3 i=4 i=5 i=6 i=7
49* 51 49* 51
9.4 简单选择排序算法
以顺序表作为存储结构的简单选择排序算法
void SelectSort(SqList &L) {//对顺序表作简单选择排序 for(i for(i= =1; 1;ii< <L.ength; L.ength;i++) i++){{ i, k <= k++) for(k for(k= =i+1, i,jj=i; =i; j= ki; <= k L.length; <= L.length; L.length; k++) k++) if (L.r[k].key < L.r[j].key) j j == k; k; if if(j (j!= !=i) i){L.r[i] {L.r[i]← ←→ →L.r[j];} L.r[j];} } //for }//if
堆的定义
对于n个元素的序列{k1,k2,...,kn},当且仅当满足以 下关系时,称之为堆。
或
k i k 2i k i k 2i 1
k i k 2i k i k 2i 1
r2i
ri
n i 1, 2, . . . , 2
r2i+1
9.4 堆排序
} // SelectSort
分析简单选择排序算法中关键字的比较次数和记录移动次数
在逆序情况下 元素的比较次数: n(n-1)/2 元素的移动次数为:3(n-1)
在正序情况下 元素的比较次数: n(n-1)/2 元素的移动次数为:0
9.4 简单选择排序算法分析
以顺序表作为存储结构的简单选择排序算法 – 时间复杂度:O(n2)
12
36 85 47 30 24 91 53 36
比较
比较-交换
交换堆顶元素与序 列末端的元素
24
91 85 12 47
30
53
输出堆顶元素后,将剩余元素重新调整为一个新堆的方法 是:从树根开始,若以某结点为根的子树不是堆,则将其 孩子中的较小者与之交换,即将非堆的子树推向叶子方向 24
交换
继续向叶子方向调整 91 53 36 36 85 12 47 91 24 24 30 53 30 比较
9.4 堆排序算法(筛选算法)
typedef SqList HeapType; //堆采用顺序存储结构
(HeapType &H, int s, int m) {
void HeapAdjust
// H.r[s .. m]中除H.r[s].key外均满足堆的定义 // 调整H.r[s]的关键字,使H.r[s .. m]成为一个大顶堆
34 34
∞
49 49
28 ∞
31 31
52
51
49* 49*
34 31
31
2. 树形选择排序的缺陷
– 需要较多的辅助空间 – 存在与“∞”进行比较的冗余比较
34
34 34 31
∞
49
49
28 ∞
31
31
52
51
49*
49*
31
3. 堆排序(Heap Sort)
– 只需要一个元素的辅助空间 – 算法的时间复杂度为O(nlogn)
//较大的孩子结点值换到父结点位置
//rc应插入的位置在s处
} // HeapAdjust
9.4 堆排序算法(续)
typedef SqList HeapType; //堆采用顺序存储结构
void HeapSort ( HeapType &H) { //对顺序表H进行堆排序 for ////把 H建成大顶堆 for( (i i==H. H.length/2; length/2; i i>>0; 0; --i) --i) 把H建成大顶堆 HeapAdjust HeapAdjust((H, H,i, i,H. H.length); length); for ( i = H. length; i > 1; --i) { H.r[1] .r[i];i// 堆顶记录和当前未排子序列中最后一个记录相交换 for ( i =←→H H. length; > 1; --i) { HeapAdjust (H, 1, // i 堆顶记录和当前未排子序列中最后一个记录相交换 - 1); //将H. r[l .. i - 1] 重新调整为大顶堆 H.r[1]←→H .r[i]; } HeapAdjust (H, 1, i - 1); //将H. r[l .. i - 1] 重新调整为大顶堆 }