收藏 分享(赏)

数据结构-9.ppt

上传人:dreamzhangning 文档编号:3313476 上传时间:2018-10-12 格式:PPT 页数:106 大小:4.12MB
下载 相关 举报
数据结构-9.ppt_第1页
第1页 / 共106页
数据结构-9.ppt_第2页
第2页 / 共106页
数据结构-9.ppt_第3页
第3页 / 共106页
数据结构-9.ppt_第4页
第4页 / 共106页
数据结构-9.ppt_第5页
第5页 / 共106页
点击查看更多>>
资源描述

1、第九章 排序,教学内容:排序的概念、插入排序、快速排序、希尔排序、选择排序、堆排序、归并排序、基数排序算法、外排序 教学重点:快速排序、堆排序、归并排序 教学难点:快速排序、堆排序、归并排序,9.1 基本概念,9.1.1 排序示例,表9-1 学生档案表,按关键字(学号)排序(升序),按年龄排序(升序),也可以是,9.1.2 概念,1. 什么是排序(sort)?将一组数据按一定的规律顺次排列起来。,存放在数据表中,按关键字排序,定义:设有记录序列: R1、R2 Rn 其相应的关键字序列为: K1、K2 Kn ; 若存在一种确定的关系: Kx = Ky = = Kz则将记录序列 R1、R2 Rn

2、排成按该关键字有序的序列: Rx、Ry Rz 的操作,称之为排序。,2排序码(Sort Key),是排序依据的记录中的一个属性。它可以是任何一种可比的有序数据类型,它可以是记录的关键字,也可以是任何非关键字。,3. 内(部)排序、外(部)排序,若待排序记录都在内存中,称为内部排序; 若待排序记录一部分在内存,一部分在外存,则称为外部排序。,注:外部排序时,要将数据分批调入内存来排序,中间结果还要及时放入外存,显然外部排序要复杂得多。,4.排序算法的评价 时间效率时间复杂度 大多数排序算法都有两个基本的操作: (1)比较两个排序码 (2)将记录从一个位置移动到另一个位置 空间效率占内存辅助空间的

3、大小 稳定性若两个记录A和B的关键字值相等,但排序后A、B的先后次序保持不变,则称这种排序算法是稳定的。,5内排序种类,按排序的规则不同,可分为5类:,d关键字的位数(长度),按排序算法的时间复杂度不同,可分为3类:简单的排序算法:时间效率低,O(n2)先进的排序算法: 时间效率高,O( nlog2n )基数排序算算法:时间效率高,O( dn),约定:大多数排序算法都是针对顺序表结构的,并且在没有声明的情形下,所有排序都按排序码的值递增排列。,typedef struct /定义被排序记录结构类型KeyType key ; /排序码 InfoType otherinfo; /其它数据项 Rec

4、ordType ;,typedef struct /定义顺序表类型RecordType r MAXSIZE +1 ; /存储带排序记录的顺序表/r0作哨兵或缓冲区int length ; /顺序表的长度 SqList ;,# define MAXSIZE 20 /设记录不超过20个 typedef int KeyType ; /设排序码为整型量,9.2 插入排序,插入排序的基本思想:,插入排序有多种具体实现算法:直接插入排序二分法(折半)插入排序希尔排序,每步将一个待排序的对象,按其排序码大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。,简言之:边插入边排序,保证子序列

5、中随时都是排好序的。,一、直接插入排序,新元素插入到哪里?,例1:排序码序列T=(13,6,3,31,9,27,5,11), 写出直接插入排序的中间过程序列。,【13】, 6, 3, 31, 9, 27, 5, 11 【6, 13】, 3, 31, 9, 27, 5, 11 【3, 6, 13】, 31, 9, 27, 5, 11 【3, 6, 13,31】, 9, 27, 5, 11 【3, 6, 9, 13,31】, 27, 5, 11 【3, 6, 9, 13,27, 31】, 5, 11 【3, 5, 6, 9, 13,27, 31】, 11 【3, 5, 6, 9, 11,13,27

6、, 31】,在已形成的有序表中顺序查找,并在适当位置插入,把原来位置上的元素向后顺移。,例2:排序码序列T= (21,25,49,25*,16,08), 请写出直接插入排序的具体实现过程。,*表示后一个25,21,i=2,i=3,i=5,i=4,i=6,25,25,25,49,49,49,25*,49,16,16,08,49,解:假设该序列已存入一维数组V7中,将V0作为“哨兵”单元。排序执行过程为:,初态:,16,25,21,16,完成!,直接插入排序算法,void Insertsort(SqList /将暂存在r0中的记录插入到正确位置 ,直接插入排序的算法分析1.时间复杂度分析 最好情况

7、 (待排序列为正序) 比较次数: n1 移动次数: 2(n-1) 最坏情况(待排序列为逆序)平均情况:比较次数和移动次数约为n2/4 故:T(n) O(n2),2.空间复杂度 S(n)O(1) 3.算法的稳定性: 该算法是稳定的排序算法,二、折半插入排序,基本思想 在有序表中采用折半查找的方法查找待排元素的插入位置。 其处理过程: 先将第一个元素作为有序序列,进行n1次插入; 每次用折半查找的方法查找待排元素的插入位置,将待排元素插入。,算法描述void BInsertSort(SqList /插入ri ,算法分析 时间复杂度: 折半插入算法的比较次数比直接插入查找的最坏情况好、最好的情况坏

8、两种方法的元素的移动次数相同,因此折半插入排序的时间复杂度仍为O(n2)。 空间复杂度 S(n)O(1) 算法的稳定性:稳定,1. 基本思想 希尔排序又称为“缩小增量排序”,是1959年由D.L.Shell提出来的。 思路:分组、组内直接插入排序;组数逐次减小;组数=1,结束。 注意: 小组的构成不是简单地“逐段分割”,而是将相隔某个增量dk的记录组成一个小组,让增量dk逐趟缩短,直到dk1为止。,三、希尔(Shell)排序,2.算法过程: (1) 取定一个整数d1作为第一个增量,将全部的n个记录分成d1个组,将所有间距为d1的记录分为同一组,并对每一组采用直接插入法排序; (2) 取一个新的

9、增量d2(d2 d1),继续分组排序; (3) 重复(1)、(2)步,直至所取的增量dk1,即所有的记录都在同一组进行直接插入排序为止。,38,例:排序码序列 T=(49,38,65,97, 76, 13, 27, 49*,55, 04),写出希尔排序的具体实现过程。,初态:,第1趟 (dk=5),第2趟 (dk=3),第3趟 (dk=1),49,13,13,49,38,27,65,49*,97,55,76,04,27,38,65,49*,97,55,13,55,76,04,55,13,27,04,27,04,49,49*,49,49*,76,38,76,65,65,97,97,13,27,0

10、4,49*,76,97,分析:开始时dk 的值较大,子序列中的对象较少,排序速度较快;随着排序进展,dk 值逐渐变小,子序列中对象个数逐渐变多,由于前面工作的基础,大多数对象已基本有序,所以排序速度仍然很快。,ri,4.算法描述 void ShellInsert(SqList ,void ShellSort(SqList k) ShellInsert(L,dltak) / ShellSort,优点:让排序码值小的元素能很快前移,且序列若基本有序时,再用直接插入排序处理,时间效率会提高。,5.算法分析 (1)时间复杂度的分析 希尔排序的时间耗费是所取的“增量”序列的函数。 到目前为止,尚未有人求

11、得一种最好的增量序列。 当增量序列取得比较合适时,排序码比较次数和记录移动次数接近于O(n(2n)2);,O(n1.25)O(1.6n1.25)经验公式,(2)空间效率:O(1)(3)算法的稳定性:不稳定,9.3 交换排序,两两比较待排序记录的排序码,如果发生逆序(即排列顺序与正确的次序相反),则交换之;直到所有记录都排好序为止。,交换排序的主要算法有:冒泡排序快速排序,交换排序的基本思想:,1.基本思想: 每趟不断将记录两两比较,若发现逆序,则交换两个记录,使排序码较小的元素逐渐从后部移向前部(就象水底的气泡一样逐渐向上冒)。 2.优点: 每趟结束时,不仅能挤出一个最大值到最后面位置,还能同

12、时部分理顺其他元素(各元素不断接近自己的位置);一旦下趟没有交换发生,还可以提前结束排序。 3. 要求:顺序存储结构,一、冒泡排序,例:排序码序列 T=(21,25,49,25*,16,08),写出冒泡排序的具体实现过程。,初态,21 25 49 25* 16 08,08 21 25 49 25* 16,第一趟,第二趟,16 21 25 49 25*,08,第三趟,21 25 25* 49,08 16,第四趟,25 25* 49,08 16 21,第五趟,25* 49,08 16 21 25,改进:,初态,21 25 49 25* 16 08,08 21 25 49 25* 16,第一趟,第二

13、趟,16 21 25 49 25*,08,第三趟,21 25 25* 49,08 16,第四趟,25 25* 49,08 16 21,第五趟,25* 49,08 16 21 25,设置标志变量flag,void Bubble_sort(SqList /若无交换则可结束冒泡排序 ,4. 算法分析 (1)时间复杂性分析: 最好情况:待排序列为正序 比较次数n1,交换次数0; 最坏情况:待排序列为逆序平均情况:由于其中的元素移动较多,所以属于内排序中速度较慢的一种。,(2)空间复杂度分析: 只在交换时用到一个缓冲单元S(n)O(1)(3)算法的稳定性: 因为冒泡排序算法只进行相邻元素间的移动,所以是

14、一个稳定的算法。,排在Ri前的记录排序码,1.基本思想: (1)从n个待排记录中任取一个记录Ri作标准,调整序列中各个记录的位置,使得:该过程为一趟快速排序。这样就确定了Ri在序列中的最终位置,同时将序列分成两个子序列。 (2)对如上确定的两个子序列分别进行快速排序,则又可确定2个记录在序列中的最后位置,同时将序列分成4个子序列。 (3)重复直至每个序列的长度均为1时,全部记录排序完毕。,二、 快速排序,排在Ri后的记录排序码,Ri.key,( ),,例1:排序码序列 T=(21,25,49,25*,16,08) 进行快速排序的过程:,21, 25, 49, 25*,16, 08,初态: 第1

15、趟: 第2趟: 第3趟:,08,16,21,25*, 25,(49),21,16,08,,( ),25*,49,25,(08),16,21,,25*,(25,49),Low=high=3,本趟停止,将支点定位并返回位置信息,例2:关键字序列 T=(21,25,49,25*,16,08),对其一趟快速排序算法的过程。,high,low,21,08,25,16,49,25*,3,21,pivotkey=21,08,25,16,49,( 08 ,16 ) 21 ( 25* , 49, 25 ),每一趟子表的形成是采用“从两头向中间逼近式” 法;,见教材P275,int Partition(SqLis

16、t /以子表的首记录作为枢轴,放入r0单元,一趟快速排序算法:,pivotkey=L.rlow.key; /取枢轴的排序码存入pivotkey变量,while(low =pivotkey ) - -high;L. rlowL.rhigh; /将比枢轴排序码小的记录交换到低端while(lowhigh /将比枢轴排序码大的记录交换到高端,L.rlow=L.r0; /枢轴记录到位 return low; /返回枢轴记录所在位置 /Partition,每一趟快速排序的处理分2步:(1)选枢轴记录;(2)分割,void QSort ( SqList ,整个快速排序的递归算法:,见教材P276,/长度1

17、,/对顺序表L中的子序列r lowhigh 作快速排序,/一趟快排,将r 一分为二,/在左子区间进行递归快排,直到长度为1,/在右子区间进行递归快排,直到长度为1,/QSort,void QuickSort ( SqList ,对顺序表L进行快速排序的操作函数为:,例3:以排序码序列(256,301,751,129,937,863,742,694,076,438)为例,写出执行快速算法的各趟排序结束时,排序码序列的状态。,原始序列: 256,301,751,129,937,863,742,694,076,438,快速排序,第1趟 第2趟 第3趟 第4趟,256,301,751,129,937,

18、863,742,694,076,438,076,129,256,751,937,863,742,694,301,438,256,076,301,129,751,256,076,129,256,438,301,694,742,694,863,937,751,076,129,256,438,301,694,742,751,863,937,076,129,256,301,301,694,742,751,863,937,438,076,129,256,301,438,694,742,751,863,937,算法QuickSort是一个递归的算法. 其递归树如图所示: Partition利用序列第一个对

19、象作为基准,将整个序列划分为左右两个子序列。 快速排序的趟数取决于递归树的高度。,快速排序算法分析:,最好的情况:每次划分所得的两个子序列的长度大致相等时。该种情况下,所需时间分析如下:T(n) cn + 2T(n/2 ) / c 是一个常数 cn + 2 ( cn/2 + 2T(n/4) ) = 2cn + 4T(n/4) 2cn + 4 ( cn/4 +2T(n/8) ) = 3cn + 8T(n/8) cn log2n + nT(1) = O(n log2n )最坏的情况:每次划分所得的两个子序列中有一个为空,另一个长为n1,这时需要n1趟快排,其递归树成为单支树。,快速排序算法分析时间

20、分析:,用第一个对象作为枢轴,快速排序退化的例子,快速排序算法分析时间分析(平均情况):,T(n) = Tpass(n) + T(k-1 ) +T(n-k) /Tpass(n)为对n个记录进行一趟快速排序Partition所需时间;/T(k-1)为对L.r1k中记录进行QSort(L,1,k-1)所需时间;/T(k-1)为对L.rk +1n中记录进行QSort(L,k+1,n)所需时间;,式(1),式(2),式(3),式(4),快速排序是所有同数量级(O(nlogn)的排序方法中,平均性能最好的。,快速排序算法分析空间分析:,快速排序是递归的,需要用一个栈存放每层递归调用时的指针和参数(新的l

21、ow和high)。最大递归调用层次数与递归树的深度一致,理想情况为 log2(n+1) 。平均的存储开销为 O(log2n)。,快速排序算法分析稳定性:,快速排序是一个不稳定的排序方法,用居中排序码对象作为基准对象,最坏情况下,退化为冒泡排序。占用附加存储(栈)将达到O(n)。 改进办法: 取每个待排序对象序列的第一个对象、最后一个对象和位置接近正中的 3 个对象,取其排序码居中者作为基准对象。,快速排序改进:“三者取中”,9.4 选择排序,基本思想 在待排记录中依次选择排序码最小的记录作为有序序列的最后一条记录,逐渐缩小范围直至全部记录选择完毕。,选择排序的主要算法有:直接选择排序堆排序,一

22、、直接选择排序 (Select Sort),1. 基本思想 直接选择排序(simple select sorting)是一种简单的排序方法,其基本思想: 第1趟:从R1Rn中选取最小值,与R1交换; 第2趟:从R2Rn中选取最小值,与R2交换; 第 i 趟:从RiRn中选取最小值,与Ri交换; 第 n -1趟: 从Rn1Rn中选取最小值,与Rn1交换.共通过n1趟,得到一个按排序码从小到大排列的有序序列,void SelectSort(SqList /SelectSort,直接选择排序算法,(1) 时间分析: 直接选择排序的排序码比较次数与记录的初始排列无关。 设有 n 个记录, 则第 i 趟

23、选择具有最小排序码记录所需的比较次数总是 n-i 次。 所以总的排序码比较次数为:,直接选择排序算法分析,记录的移动次数与序列初始排列有关。 当初始状态是正序时, 记录的移动次数为 0,达到最少。 最坏情况是每一趟都要进行交换,总移动次数为3(n-1) 所以,时间复杂度T(n)=O(n2),(2) 空间分析: 辅助空间:O(1) (3) 稳定性分析: 直接选择排序是一种不稳定的排序方法。,二、树形选择排序,从直接选择排序可知: 在n个排序码中,找出最小值需n1次比较,找出第二小值需n2次比较,找出第三小值需n3次比较, 所以,总的比较次数为:(n1)(n2)321 (n2n)2, 能否对直接选

24、择排序算法加以改进,使总的比较次数比 (n2n)2小呢?,基本思想: 与体育比赛时的淘汰赛类似,故又称为:锦标赛排序 (Tournament Sort) 首先将 n 个记录的排序码,进行两两比较,得到 n/2 个比较的优胜者(排序码小者),作为第一步比较的结果保留下来. 然后对这 n/2 个记录再进行排序码的两两比较, 如此重复直到选出一个排序码最小的记录为止,树形选择排序,Winner1,例,形成初始胜者树(最小排序码上升到根)输出冠军,并调整胜者树。,Winner2,输出亚军,并调整胜者树。,Winner3,输出第3名,并调整胜者树,Winner4,输出第4名,并调整胜者树,Winner5

25、,输出第5名,并调整胜者树,Winner6,输出第6名,并调整胜者树,Winner,输出第7、8名,比赛结束,分析: 当决出一个胜者后,要取得下一个胜者的比较只限于从根到前一趟选出的结点这一条路径上。 除选出第一名需要n-1比较次外,此后选出次小、再次小,比较都是log2n次,故其复杂度为O(n*log2n)。但是对于有n个待排记录,锦标赛算法需要2n-1个结点存放胜者树。因此,这是一个以空间换时间的算法。,改进:1964年威洛姆斯(J.Willioms)和弗洛伊德(Floyd) 对树形选择排序进行了改进提出了新的选择排序方法堆排序,使其比较次数达到树形选择排序的水平,同时又不会增加额外的存储

26、开销,只需一个记录大小的空间用于记录间的交换。,1.堆(heap)定义 n个元素的序列(k1,k2,kn),满足如下条件,称为堆。,或,小根堆,大根堆,三、堆排序,说明: 堆与完全二叉树: 如果让满足堆条件的元素序列 (k1,k2,kn)顺次排成一棵完全二叉树,则此树的特点是:树中所有结点的值均(或)其左右孩子,此树的根结点k1(即堆顶)必最大(或最小)。 从根到叶的路径上元素组成的序列为有序序列; 堆中任意子树也是堆。,例: 如序列(80,75,40,62,73,35,28,50,38,25,47,15)可以验证它满足堆的条件,下图给出其对应的完全二叉树。,2.堆排序(Heap Sort)的

27、基本思想 (1) 将原始序列建成堆(初始堆) (2) 输出堆顶元素,并调整剩余元素使之成堆 (3) 重复(2),直至所有元素均输出。,堆排序需解决的两个问题: 如何由一个无序序列建成一个堆? 如何在输出堆顶元素之后,调整剩余元素,使之成为一个新的堆?第二个问题解决方法筛选法,问题1:建初始堆。 步骤: 从最后一个非终端结点开始往前逐步调整,让每个双亲结点排序码大于(或小于)子女结点排序码,直到根结点为止。,i4,9749*,要调整,49*,97,i3,6513,要调整,13,65,i2,无需调整,i1, 4913,要调整,13,49,49,27,例:对关键字序列16,21,25,25*,08,

28、 49构造小根堆。 将原始序列画成完全二叉树的形式, 从n/2开始调整。,问题2: 方法:“筛选法” 输出堆顶元素之后,以堆中最后一个元素替代之; 然后将根结点值与左、右子树的根结点值进行比较,并与其中小者进行交换; 重复上述操作,直至叶子结点,将得到新的堆,称这个从堆顶至叶子的调整过程为“筛选”。,筛选法举例,筛选出新的“堆顶”,排序结束! 表中为排序码的逆序, 反向输出!,算法分析 (1) 时间复杂度: O(nlog2n) 初始建堆时间:整个排序过程中需要调用n1次堆顶的调整,而每次堆排序算法本身耗时为log2n; 总时间T(n)=O(n)+O(nlogn)=O(nlogn),(2)空间分

29、析,该算法的附加存储主要是在第二个for循环中用来执行对象交换时所用的一个临时对象。因此,该算法的空间复杂性为O(1)。,(3)稳定性,堆排序是一个不稳定的排序方法。,说明 堆排序适用于n 较大的情况,归并将两个或两个以上的有序表组合成一个新的有序表。 2-路归并排序 排序过程 设初始序列含有n个记录,则可看成n个有序的子序列,每个子序列长度为1; 两两合并,得到n/2个长度为2或1的有序子序列; 再两两合并,如此重复,直至得到一个长度为n的有序序列为止.,9.5 归并排序 (Merge Sort),表归并操作,二路归并排序(例1),二路归并排序(例2),算法描述 void Merge(Rcd

30、Type SR,RcdType ,void MSort(RcdType SR,RcdType ,void MergeSort(SqList /MergeSort,二路归并排序算法分析: 时间复杂度: O(nlog2n) 空间复杂度:O(n) 算法的稳定性:稳定,9.5 基数排序,基本思想 借助多关键字排序的思想对单逻辑关键字进行排序。即:用关键字不同的位值进行排序。,多关键字排序,对52张扑克牌按以下次序排序: 23A23A23A23A这就是多关键字排序。对于上例两关键字的排序,可以先按花色排序,之后再按面值排序;也可以先按面值排序,再按花色排序。,例 以扑克牌排序为例。每张扑克牌有两个“关键

31、字”:花色和面值。其顺序关系为:花色: 面值:2 3 4 5 6 7 8 9 10 J Q K A,链式基数排序 基数排序:借助“分配”和“收集”对单关键字进行排序的一种方法。 链式基数排序:用链表作存储结构的基数排序。,链式基数排序步骤(以整数型关键字为例) 设置r个队列,fi和ei分别为第i个队列的头指针和尾指针 第一趟分配对最低位关键字(个位)进行,改变记录的指针值,将链表中记录分配至r个链队列中,每个队列记录的关键字的个位相同 第一趟收集是改变所有非空队列的队尾记录的指针域,令其指向下一个非空队列的队头记录,重新将r个队列链成一个链表 重复上述两步,进行第二趟、第三趟分配和收集,分别对

32、十位、百位进行,最后得到一个有序序列 (r为基数,对整数型关键字,r=10),例,算法评价时间复杂度:基数排序中,没有排序码的比较和记录的移动,只是对链表的扫描和赋值,时间主要用在修改指针上。 每趟:将n个记录分配到队列的时间为O(n),收集的时间为O(r) 分配:O(n) 收集:O(r) 一趟基数排序时间:O(n+r) 共进行d趟基数排序过程,总时间T(n)=O(d(n+r) 其中:n记录数 d关键字位数 空间复杂度:S(n)=O(n+r)2r个队列指针+n个指针域空间基数排序是稳定的排序方法。,各种内部排序算法的比较,1.平均性能: 快速排序最省时间,但最坏情况下的时间性能不如堆排序和归并

33、排序; 堆排序和归并排序这两种方法,当n较大时,归并排序所需时间较省,但需要的辅助空间多。,如何选择合适的排序算法? 1从时间复杂度选择 对元素个数较多的排序,可以选快速排序、堆排序、归并排序; 元素个数较少时,可以选简单的排序方法。,如何选择合适的排序算法? 2从空间复杂度选择 尽量选空间复杂度为O(1)的排序方法, 其次选空间复杂度为O(logn)的快速排序方法 最后选空间复杂度为O(n)二路归并排序的排序方法。,选择合适的排序算法的一般选择规则: 1.当待排序元素的个数n较大,排序码分布是随机,而对稳定性不做要求时,则采用快速排序为宜。 2.当待排序元素的个数n大,内存空间允许,且要求排序稳定时,则采用二路归并排序为宜。3.当待排序元素的个数n大,排序码分布可能会出现正序或逆序的情形,且对稳定性不做要求时,则采用堆排序或二路归并排序为宜。,4.当待排序元素的个数n小,元素基本有序或分布较随机,且要求稳定时,则采用直接插入排序为宜。 5.当待排序元素的个数n小,对稳定性不做要求时,则采用直接选择排序为宜,若排序码不接近逆序,也可以采用直接插入排序。冒泡排序一般很少采用。,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 大学课件

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报