11_堆及堆排序

合集下载

堆、栈的概念与理解

堆、栈的概念与理解

1、从数据结构层次理解,栈是一种先进后出的线性表,只要符合先进后出的原则的线性表都是栈。至于采用的存储方式(实现方式)是顺序存储(顺序栈)还是链式存储(链式栈)是没有关系的。堆则是二叉树的一种,有最大堆最小堆,排序算法中有常用的堆排序。
2、从系统层次理解,栈是系统为运行的程序分配的先进后出的存储区域。在学习bootloader时知道,在上电后初始化阶段要为各个工作模式下分配堆 栈,这里的堆栈实际上就是指stack,堆栈的说法只是因为历史的原因。在执行函数时,函数内部局部变量的存储单元可以在栈上创建(针对CISC架构而 言,RISC架构下,局部变量的存储单元是在寄存器上创建),函数执行结束时这些存储单元自动被释放。堆是系统管理的可以被程序利用的全局存储空间,动态 内存分配就是从堆上分配。
什么是堆什么是栈
一 英文名称
堆和栈是C/C++编程中经常遇到的两个基本概念。先看一下它们的英文表示:
堆――heap
栈――stack
二 从数据结构和系统两个层次理解
在具体的C/C++编程框架中,这两个概念并不是并行的。深入到汇编级进行研究就会发现,栈是机器系统提供的数据结构,而堆是由C/C++函数库提供的。这两个概念可以从数据结构和系统两个层次去理解:
具体地说,现在计算机(串行执行机制),都直接在代码层次支持栈这种数据结构。这体现在,有专门的寄存器指向栈所在的地址,有专门的机器指令完成数据入栈 出栈的操作。比如ARM指令中的stmfd和ldmfd。因为栈内存分配运算内置于处理器的指令集中,所以效率很高,但是支持的数据有限,一般是整数、指 针、浮点数等系统直接支持的数据类型,并不直接支持其他的数据结构。在CISC中,对子程序的调用就是利用栈来完成的。C/C++中的自动变量也是直接利 用栈的例子,这就是为什么当函数返回时,该函数的自动变量失效的原因(因为栈恢复了调用前的状态)。在RISC下,这些都是通过寄存器来完成的。这些留待 第二部分总结中详细阐述。

数据结构复习题汇总

数据结构复习题汇总

数据结构复习题汇总黄⽼师:题型结构如下:单项选择题,15⼩题,30分;填空题,5⼩题,10分;综合应⽤题,50分(树、图、查找)算法设计与分析,2选1,10分(线性结构)试卷中⼀些算法只给英⽂名称;考查范围(⿊体字为建议的重点考查内容;红字为备注;蓝字为拟纳⼊的考研⼤纲内容)⼀、绪论(⼀)算法、数据结构基本概念(⼆)算法分析中O(f(n))符号的含义(三)时间复杂度简单分析表⽰⼆、线性表(⼀)线性表的定义和基本操作(⼆)线性表的实现1.顺序存储2.链式存储3.线性表的应⽤三、栈、队列(⼀)栈和队列的基本概念(⼆)栈和队列的顺序存储结构(三)栈和队列的链式存储结构(四)栈和队列的应⽤四、树与⼆叉树(⼀)树的概念(⼆)⼆叉树1.⼆叉树的定义及其主要特征2.⼆叉树的顺序存储结构和链式存储结构3.⼆叉树的遍历及应⽤(三)树、森林1. 森林与⼆叉树的转换2. 树的存储结构;3.树和森林的遍历4.线索⼆叉树的基本概念和构造(四)⼆叉树的应⽤1.哈夫曼(Huffman)树和哈夫曼编码2.⼆叉排序树五、图(⼀)图的基本概念(⼆)图的存储及基本操作1.邻接矩阵法2.邻接表法(三)图的遍历1.深度优先搜索2.⼴度优先搜索(四)图的基本应⽤1.最⼩(代价)⽣成树2.最短路径3.拓扑排序4.关键路径六、查找(⼀)查找的基本概念(⼆)顺序查找法(三)折半查找法(四)⼆叉查找树及其基本操作(只考察基本概念)(五)平衡⼆叉树(只考察基本概念)(六)散列(Hash)表(七)查找算法的分析及应⽤七、排序(⼀)排序的基本概念(⼆)直接插⼊排序(三)⽓泡排序(bubble sort)(四)简单选择排序(五)希尔排序(shell sort)(六)快速排序(七)堆排序(⼋)⼆路归并排序(merge sort)(九)各种排序算法的⽐较(⼗)排序算法的应⽤选择题1、顺序队列的出队操作,正确修改队⾸指针的是( B )(A)sq.front = (sq.front+1)%maxsize; (B)sq.front = sq.front+1;(C)sq.rear = (sq. rear +1)%maxsize; (D)sq.rear = sq. rear +1;2、⾮空的循环单链表head的尾结点(由指针p指)满⾜( C )(A)p->next = NULL (B)p = NULL (C)p->next = head (D)p = head3、在单键表中,删除p所指结点的直接后继,其中指针修改为( A )(A)p->next = p->next ->next; (B)p = p->next; p->next = p->next->next;(C)p->next = p->next; (D)p = p->next ->next;4、通常要求同⼀逻辑结构中的所有数据元素具有相同的特性,这意味着( B )(A)数据元素具有同⼀特点(B)不仅数据元素所包含的数据项的个数要相同,⽽且对应数据项的类型也要⼀致(C)每个数据元素都⼀样(D)数据元素所包含的数据项的个数要相等5、关于线性表,下列说法正确的是( D )(A)每个元素都有⼀个直接前驱和直接后继(B)线性表中⾄少要有⼀个元素(C)表中诸元素的排列顺序必须是由⼩到⼤或由⼤到⼩的(D)除第⼀元素和最后⼀个元素外,其余每个元素都有⼀个且仅有⼀个直接前驱和直接后继6、带头结点的单链表,其表头指针为head,则该单链表为空的判断条件是( B )(A)head == NULL (B)head->next == NULL(C)head->next == head (D)head !== NULL7、含n个顶点的连通图中的任意⼀条简单路径,其长度不可能超过(C )(A)1 (B)n/2 (C)n-1 (D)n8、设有⼀个顺序栈S,元素S1, S2, S3, S4, S5, S6依次进栈,如果6个元素出栈的顺序是S2, S3, S4, S6, S5, S1,则栈的容量⾄少应该是( B )(A)2 (B)3 (C)5 (D)69、设深度为k的⼆叉树上只有度为0和度为2的结点,则这类⼆叉树上所含结点的总数最少为( C )个(A)k+1 (B)2k (C)2k -1 (D)2k +110、从具有n个结点的单链表中查找指定结点时,若查找每个结点的概率相等,在查找成功的情况下,平均需要⽐较( D )个结点。

数据结构试题及答案(2)

数据结构试题及答案(2)

数据结构试题一、单选题(每题 2 分,共20分)1.1. 对一个算法的评价,不包括如下( B )方面的内容。

A.健壮性和可读性B.并行性 C.正确性 D.时空复杂度2.2. 在带有头结点的单链表HL中,要向表头插入一个由指针p指向的结点,则执行( A )。

A. p->next=HL->next; HL->next=p;B. p->next=HL; HL=p;C. p->next=HL; p=HL;D. HL=p; p->next=HL;3.3. 对线性表,在下列哪种情况下应当采用链表表示?( B )A.经常需要随机地存取元素B.经常需要进行插入和删除操作C.表中元素需要占据一片连续的存储空间D.表中元素的个数不变4.4. 一个栈的输入序列为 1 2 3,则下列序列中不可能是栈的输出序列的是( C )A. 2 3 1B. 3 2 1C. 3 1 2D. 1 2 35.5. AOV网是一种( D )。

A.有向图 B.无向图 C.无向无环图D.有向无环图6.6. 采用开放定址法处理散列表的冲突时,其平均查找长度( B )。

A.低于链接法处理冲突 B. 高于链接法处理冲突C.与链接法处理冲突相同 D.高于二分查找7.7. 若需要利用形参直接访问实参时,应将形参变量说明为( D )参数。

A.值 B.函数 C.指针 D.引用8.8. 在稀疏矩阵的带行指针向量的链接存储中,每个单链表中的结点都具有相同的( A )。

A.行号B.列号 C.元素值 D.非零元素个数9.9. 快速排序在最坏情况下的时间复杂度为( D )。

A.O(log2n) B.O(nlog2n) C.O(n) D.O(n2)10.10. 从二叉搜索树中查找一个元素时,其时间复杂度大致为( C )。

A. O(n)B. O(1)C. O(log2n) D. O(n2)二、运算题(每题 6 分,共24分)1. 1. 数据结构是指数据及其相互之间的_对应关系(联系)。

c++排序算法

c++排序算法

当n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序、堆排序或归并排序序。

快速排序:是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;1. 插入排序—直接插入排序(Straight Insertion Sort)基本思想:将一个记录插入到已排序好的有序表中,从而得到一个新,记录数增1的有序表。

即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。

要点:设立哨兵,作为临时存储和判断数组边界之用。

直接插入排序示例:如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。

所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。

算法的实现:效率:时间复杂度:O(n^2).其他的插入排序有二分插入排序,2-路插入排序。

2. 插入排序—希尔排序(Shell`s Sort)希尔排序是1959 年由D.L.Shell 提出来的,相对直接排序有较大的改进。

希尔排序又叫缩小增量排序基本思想:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。

操作方法:1.选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;2.按增量序列个数k,对序列进行k 趟排序;3.每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。

仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

希尔排序的示例:算法实现:我们简单处理增量序列:增量序列d = {n/2 ,n/4, n/8 .....1} n为要排序数的个数即:先将要排序的一组记录按某个增量d(n/2,n为要排序数的个数)分成若干组子序列,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。

最新信息学奥赛一本通-第3章--第3节-堆及其应用(C++版)精品ppt课件精选全文

最新信息学奥赛一本通-第3章--第3节-堆及其应用(C++版)精品ppt课件精选全文

for(i = 1 ; i <= n ; i++) {
cin >> x; put(x); } for(i = 1 ; i < n ; i++) { x = get(); y = get(); ans += x + y; put(x + y); } cout << ans << endl; }
//建堆,其实直接将数组排序也是建堆方法之一
即:
get和put操作的复杂度均为log2n。所以建堆复杂度为nlog2n。合 并果子时,每次需要从堆中取出两个数,然后再加入一个数,因此一 次合并的复杂度为3log2n,共n-1次。所以整道题目的复杂度是nlog2n。
【参考程序】
#include <iostream> #include <cstdio> using namespace std; int heap_size, n; int heap[30001]; void swap(int &a, int &b) //加&后变量可修改 {
if(heap[now] >= heap[next]) break;
swap(heap[now], heap[next]);
now = next;
}
}
使用C++标准模板库STL(需要头文件<algorithm>):
void put(int d)
{
heap[++heap_size] = d;
//push_heap(heap + 1, heap + heap_size + 1);

数据结构复习题 有答案的打印版

数据结构复习题 有答案的打印版

一、选择题1.下面关于线性表的叙述中,错误的是哪一个?( B )A.线性表采用顺序存储,必须占用一片连续的存储单元。

B.线性表采用顺序存储,便于进行插入和删除操作。

C.线性表采用链接存储,不必占用一片连续的存储单元。

D.线性表采用链接存储,便于插入和删除操作。

3.线性表是具有n个( C )的有限序列(n>0)。

A.表元素B.字符C.数据元素D.数据项E.信息项2.若某线性表最常用的操作是存取任一指定序号的元素和在最后进行插入和删除运算,则利用( A )存储方式最节省时间。

A.顺序表B.双链表C.带头结点的双循环链表D.单循环链表3.某线性表中最常用的操作是在最后一个元素之后插入一个元素和删除第一个元素,则采用( D )存储方式最节省运算时间。

A.单链表B.仅有头指针的单循环链表C.双链表D.仅有尾指针的单循环链表4. 静态链表中指针表示的是( C ).A.内存地址B.数组下标C.下一元素地址D.左、右孩子地址5. 链表不具有的特点是( B )A.插入、删除不需要移动元素B.可随机访问任一元素C.不必事先估计存储空间D.所需空间与线性长度成正比1. 对于栈操作数据的原则是(B )。

A. 先进先出B. 后进先出C. 后进后出D. 不分顺序2. 有六个元素6,5,4,3,2,1 的顺序进栈,问下列哪一个不是合法的出栈序列?( A )A. 5 4 3 6 1 2B. 4 5 3 1 2 6C. 3 4 6 5 2 1D. 2 3 41 5 63. 设栈的输入序列是1,2,3,4,则(D )不可能是其出栈序列。

A. 1,2,4,3,B. 2,1,3,4,C. 1,4,3,2,D. 4,3,1,2,E. 3,2,1,4,1. 已知数组A[0..9,0..9]的每个元素占5个存储单元,将其按行优先次序存储在起始地址为1000的连续的内存单元中,求A[6,8]的地址。

13402. 已知二维数组A[1..10,0..9]中每个元素占4个单元,在按行优先方式将其存储到起始地址为1000的连续存储区域时,求A[5,9]的地址。

排序算法稳定性比较

排序算法稳定性比较

这几天笔试了好几次了,连续碰到一个关于常见排序算法稳定性判别的问题,往往还是多选,对于我以及和我一样拿不准的同学可不是一个能轻易下结论的题目,当然如果你笔试之前已经记住了数据结构书上哪些是稳定的,哪些不是稳定的,做起来应该可以轻松搞定。

本文是针对老是记不住这个或者想真正明白到底为什么是稳定或者不稳定的人准备的。

首先,排序算法的稳定性大家应该都知道,通俗地讲就是能保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同。

在简单形式化一下,如果Ai = Aj, Ai原来在位置前,排序后Ai还是要在Aj位置前。

其次,说一下稳定性的好处。

排序算法如果是稳定的,那么从一个键上排序,然后再从另一个键上排序,第一个键排序的结果可以为第二个键排序所用。

基数排序就是这样,先按低位排序,逐次按高位排序,低位相同的元素其顺序再高位也相同时是不会改变的。

另外,如果排序算法稳定,对基于比较的排序算法而言,元素交换的次数可能会少一些(个人感觉,没有证实)。

回到主题,现在分析一下常见的排序算法的稳定性,每个都给出简单的理由。

(1)冒泡排序冒泡排序就是把小的元素往前调或者把大的元素往后调。

比较是相邻的两个元素比较,交换也发生在这两个元素之间。

所以,如果两个元素相等,我想你是不会再无聊地把他们俩交换一下的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。

(2)选择排序选择排序是给每个位置选择当前元素最小的,比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二小的,依次类推,直到第n-1个元素,第n个元素不用选择了,因为只剩下它一个最大的元素了。

那么,在一趟选择,如果当前元素比一个元素小,而该小的元素又出现在一个和当前元素相等的元素后面,那么交换后稳定性就被破坏了。

比较拗口,举个例子,序列5 8 5 2 9,我们知道第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序不是一个稳定的排序算法。

关于堆排序、归并排序、快速排序的比较

关于堆排序、归并排序、快速排序的比较

关于堆排序、归并排序、快速排序的⽐较时间复杂度:堆排序归并排序快速排序最坏时间 O(nlogn) O(nlogn) O(n^2)最好时间 O(nlogn) O(nlogn) O(nlogn)平均时间 O(nlogn) O(nlogn) O(nlogn)辅助空间 O(1) O(n) O(logn)~O(n)从时间复杂度看堆排序最好有⼈说代码实现后,数据量⾜够⼤的时候,快速排序的时间确实是⽐堆排序短解释是,对于数组,快速排序每下⼀次寻址都是紧挨当前地址的,⽽堆排序的下⼀次寻址和当前地址的距离⽐较长。

⽹友解答:1#4种⾮平⽅级的排序:希尔排序,堆排序,归并排序,快速排序我测试的平均排序时间:数据是随机整数,时间单位是秒数据规模快速排序归并排序希尔排序堆排序1000万 0.75 1.22 1.77 3.575000万 3.78 6.29 9.48 26.541亿 7.65 13.06 18.79 61.31堆排序是最差的。

这是算法硬伤,没办法的。

因为每次取⼀个最⼤值和堆底部的数据(记为X)交换,重新筛选堆,把堆顶的X调整到位,有很⼤可能是依旧调整到堆的底部(堆的底部X显然是⽐较⼩的数,才会在底部),然后再次和堆顶最⼤值交换,再调整下来。

从上⾯看出,堆排序做了许多⽆⽤功。

⾄于快速排序为啥⽐归并排序快,我说不清楚。

2#算法复杂度⼀样只是说明随着数据量的增加,算法时间代价增长的趋势相同,并不是执⾏的时间就⼀样,这⾥⾯有很多常量参数的差别,即使是同样的算法,不同的⼈写的代码,不同的应⽤场景下执⾏时间也可能差别很⼤。

快排的最坏时间虽然复杂度⾼,但是在统计意义上,这种数据出现的概率极⼩,⽽堆排序过程⾥的交换跟快排过程⾥的交换虽然都是常量时间,但是常量时间差很多。

3#请问你的快快速排序是怎么写的,我写的快速排序,当测试数组⼤于5000的时候就栈溢出了。

其他的⼏个排序都对着,不过他们呢没有⽤栈。

这是快速排序的代码,win7 32位,vs2010.1int FindPos(double *p,int low,int high)2 {3double val = p[low];4while (low<high)5 {6while(low<high&&p[high]>=val)7 high--;8 p[low]=p[high];9while(low<high&&p[low]<val)10 low++;11 p[high]=p[low];12 }13 p[low]=val;14return low;15 }16void QuickSort(double *a,int low,int high)17 {18if (!a||high<low)19return;2021if (low<high)22 {23int pos=FindPos(a,low,high);24 QuickSort(a,low,pos-1);25 QuickSort(a,pos+1,high);26 }27 }……7#谁说的快排好啊?我⼀般都⽤堆的,我认为堆好。

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

(13,38,27,50,76,65,49,97) 13,38,27,50,76,65,49,97)
97 27 49 13 输出:13 50 38 76 65 27 49 13 输出:13 50 38 76 65 27 49 97
97 38 50 13 输出:13 27 76 65 49 27 13 97 50 76
38 49 65 27 13 输出:13 27 97 50 76
65 49 38 27
输出:13 27 38
8
49 50 97 13 输出:13 27 38 76 38 65 27 13 97 50 49
76 65 38 27 13 输出:13 27 38 49 97 76 49
50 65 38 27
14
97 65 38 27
输出:13 27 38 49 50 65 76
10
算法 :堆调节 void HeapAdjust (HeapType &H, int s, int m) { // 已知H.r[s..m]中记录的关键字除H.r[s].key之外均满足堆的定义,本函数依据 已知H.r[s..m]中记录的关键字除 中记录的关键字除H.r[s].key之外均满足堆的定义 之外均满足堆的定义,
{12, 36, 27, 65, 40, 34, 98, 81, 73, 55, 49} 是小顶堆 {12, 36, 27, 65, 40, 14, 98, 81, 73, 55, 49} 不是堆 14,
1
若将该数列视作完全二叉树,则 r2i 是 ri 的左孩子; 的左孩子; 若将该数列视作完全二叉树, 的右孩子。 r2i+1 是 ri 的右孩子。
4
typedef SqTable heapType
void HeapSort ( HeapType &H ) CreateHeap(H); //建立初始堆 { CreateHeap(H); //建立初始堆 H.r[1] H.r[n]; //堆顶元素与最后一个元素交换 //堆顶元素与最后一个元素交换 for(i=nfor(i=n-1; i>1; i--) //连续进行堆调节和交换 i--) //连续进行堆调节和交换 { HeapAdjust(H); HeapAdjust(H); H.r[1] H.r[i]; } } 堆排序需解决的两个问题: 堆排序需解决的两个问题:
//建堆 //建堆
左/右子树都已经调整为堆 void CreateHeap(HeapType &H) { for (i=H.length/2;i>0;i--) (i=H.length/2;i>0;i--) 最后只要调整根结点,使整个二叉树是个“堆” HeapAdjust(H, i, H.length); 即可。
11
建堆是一个从下往上进行“筛选”的过程。 建堆是一个从下往上进行“筛选”的过程。 例如: 原始序列为(40,55,49,73,12,27,78,81,64,36) 例如 原始
从第一个非叶节点开始调节
98 40 98 49 36 12 27 40 49 98
81 55 81 73 55 73 81 64 12 36
6
大顶堆调节过程: 大顶堆调节过程:
大顶堆的排序结果是升序排序
12 73 81 64 73 55 12 64 98 12 36
81 12 98
比较
49 27 40
是大顶堆
输出98( 98 和 12 进行互换)之后,它就不是堆了 不 需要对它进行“筛选”
7
例:小顶堆 13 38 50 97 76 65
13 27 38 27 76 65 49
83
38
11
9 97
50
堆序列是完全二叉树,则堆顶元素 堆序列是完全二叉树, 完全二叉树的根)必为序列中n (完全二叉树的根)必为序列中n 个元素的最小值或最大值
3
堆排序
堆排序即是利用堆的特性对记录序列进行排序的 一种排序方法
堆排序的过程
对n个数据的原始无序序列建堆,输出堆顶元素 个数据的原始无序序列建堆, 将剩下的n 个元素调整为堆, 将剩下的n-1个元素调整为堆,输出堆顶元素 将剩下的n 个元素调整为堆, 将剩下的n-2个元素调整为堆,输出堆顶元素 …….. …….. 剩下的最后一个元素, 剩下的最后一个元素,本身就是堆
13
堆排序的时间复杂度分析: 堆排序的时间复杂度分析:
1. 对深度为 k 的堆,“筛选”所需进行的关键字 的堆, 筛选” 比较的次数至多为2(k 1); 2(k比较的次数至多为2(k-1); 2. 对 n 个关键字,建成深度为h(=log2n+1)的堆, 个关键字, (= +1)的堆 的堆, 所需进行的关键字比较的次数至多 4n; 3. 调整“堆顶”n-1次,总共进行的关键字比较的次 调整“堆顶” 数不超过 2 (log2(n-1)+log2(n-2)+…+log22)<2n(log2n) ( (n(n因此,堆排序的时间复杂度为O(nlogn)。 因此,堆排序的时间复杂度为O(
// 关键字的大小对H.r[s]进行调整,使H.r[s..m]成为一个大顶堆(对其中记录的关 关键字的大小对H.r[s]进行调整 进行调整, H.r[s..m]成为一个大顶堆 成为一个大顶堆( 键字而言) 键字而言)
rc = H.r[s]; // 暂存根结点的记录 for ( j=2*s; j<=m; j*=2 ) { // 沿key较大的孩子结点向下筛选 key较大的孩子结点向下筛选 if ( j<m && H.r[j].key<H.r[j+1].key ) ++j; // j为key较大孩子记录的下标 j为key较大孩子记录的下标 if ( rc.key >= H.r[j].key ) break; // 不需要调整 H.r[s] = H.r[j]; s = j; // 把大关键字记录往上调 } H.r[s] = rc; // 回移筛选下来的记录 } // HeapAdjust
堆的定义
完全二叉树的性质? 完全二叉树的性质?
堆是满足下列性质的数据序列{ 堆是满足下列性质的数据序列{r1, r2, …,rn}:
r i ≤r r i ≥r 2 i 2 i (小顶堆 或 小顶堆) (大顶堆 大顶堆) 小顶堆 大顶堆 2 i r i+1 ≤ r i r2i+1 ≥ r
输出:13 27 38 49
97 76 50 13 输出:13 27 38 49 50 49 38 65 27 13 50 76 49
65 97 38 27 13 输出:13 27 38 49 50 50 76 49
97 65 38 27
输出:13 27 38 49 50 65
9
76 97 50 13 输出:13 27 38 49 50 65 97 76 50 13 输出:13 27 38 49 50 65 76 97 49 38 65 27 49 38 65 27 13 50 76 49
ri r2i
例如: 例如
12 36 65 81 73 55 40 49 14 34 27 98
2
r2i+1
{12, 36, 27, 65, 40, 34, 98, 81, 73, 55, 49}
不 是堆
例 (96,83,27,38,11,9) 96,83,27,38,11,
96
例 (13,38,27,50,76,49,97) 13,38,27,50,76,65,49,97)
如何由一个无序序列建成一个堆? 如何由一个无序序列建成一个堆? 如何在输出堆顶元素之后,调整剩余元素, 如何在输出堆顶元素之后,调整剩余元素,使 之成为一个新的堆? 之成为一个新的堆? 筛选
5
第二个问题解决方法——筛选 第二个问题解决方法——筛选
所谓“筛选”指的是,对一棵左/ 所谓“筛选”指的是,对一棵左/右子树均为堆的 完全二叉树, 调整” 完全二叉树,“调整”根结点使整个二叉树也成为 一个堆 方法:输出堆顶元素之后,以堆中最后一个元素替 方法:输出堆顶元素之后, 代之;然后将根结点值与左、 代之;然后将根结点值与左、右子树的根结点值进 行比较,并与其中小者进行交换;重复上述操作, 行比较,并与其中小者进行交换;重复上述操作, 直至叶子结点,将得到新的堆, 直至叶子结点,将得到新的堆,称这个从堆顶至叶 子的调整过程为“筛选” 子的调整过程为“筛选”
}
12
算法 :堆排序 void HeapSort ( HeapType &H ) { // 对顺序表H进行堆排序。 对顺序表H进行堆排序。 for ( i=H.length/2; i>0; --i ) --i // 把H.r[1..H.length]建成大顶堆 H.r[1..H.length]建成大顶堆 HeapAdjust ( H, i, H.length ); w=H.r[1] ; H.r[1]= H.r[H.length]; H.r[H.length]=w; //交换"堆顶"和"堆底"的记录 //交换 堆顶" 交换" 堆底" for ( i=H.length-1; i>1; --i ) { i=H.length--i HeapAdjust(H, 1, i); // 从根开始调整,将H 重新调整为大顶堆 从根开始调整, w=H.r[1]; H.r[1]=H.r[i]; H.r[i]=w; // 相互交换 } }
相关文档
最新文档