第10章 内部排序
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
待排记录的数据类型: 待排记录的数据类型 #define MAXSIZE 20 typedef struct{ KeyType key; }RedType; typedef struct{ RedType r[MAXSIZE+1]; int length; }SqList; /*待排序文件中记录的个数 待排序文件中记录的个数*/ 待排序文件中记录的个数 /*待排序文件类型 待排序文件类型*/ 待排序文件类型 /*记录类型的定义 记录类型的定义*/ 记录类型的定义 /*文件中记录个数的最大值 文件中记录个数的最大值*/ 文件中记录个数的最大值 typedef int KeyType; /*定义排序码类型为整数类型 定义排序码类型为整数类型*/ 定义排序码类型为整数类型
二、堆排序 ——只需要一个记录大小的辅助空间 只需要一个记录大小的辅助空间, ——只需要一个记录大小的辅助空间,每个待排序 的记录仅占有一个存储空间 堆是一个序列{k 它满足下面的条件: 堆是一个序列{k1,k2,…,kn},它满足下面的条件: 并且k i=1,2,…,n/2 ki≤k2i并且ki≤k2i+1,当i=1,2,…,n/2 小根堆 i=1,2,…,n/2 ki≥k2i并且ki≥k2i+1,当i=1,2,…,n/2 大根堆 k 并且k k 采用顺序方式存储这个序列, 采用顺序方式存储这个序列,就可以将这个序列的每 一个元素k 看成是一棵有n个结点的完全二叉树的第i 一个元素ki看成是一棵有n个结点的完全二叉树的第i 个结点,其中k 是该二叉树的根结点。 个结点,其中k1是该二叉树的根结点。
设待排序的7记录的排序码为{312,126,272,226, 设待排序的7记录的排序码为{312,126,272,226, {312 28,165,123},初始让d=7/2=3 以后每次让d d=7/2=3, 28,165,123},初始让d=7/2=3,以后每次让d缩小 一半, 一半,其排序过程如图所示
堆排序算法: 堆排序算法: 1、构建堆 2、输出堆顶元素 筛选” 3、“筛选”堆 构建堆的算法: 构建堆的算法: 1、将无序序列按层次顺序构建一棵完全二叉树 由最后一个非终端结点t开始, 2、由最后一个非终端结点t开始, t=min(t,t.lchild,t.rchild)或 t=min(t,t.lchild,t.rchild)或 t=max(t,t.lchild,t.rchild) “筛选”堆的算法: 筛选”堆的算法: 从堆顶开始,将堆顶元素t和它的左、右子树比较, 1、从堆顶开始,将堆顶元素t和它的左、右子树比较, t=min(lchild,rchild)或 t=min(lchild,rchild)或 t=max(lchild,rchild) 2、将发生改变的那棵子树按相同方法处理
void InsertSort(SqList &L) { for(i=2;i<=L.length;i++) /*依次插入从第 个开始的所有元素 依次插入从第2个开始的所有元素 依次插入从第 个开始的所有元素*/ if(LT(L.r[i]).key,L.r[i-1].key) { L.r[0]=L.r[i]; /*设置哨兵 设置哨兵*/ 设置哨兵 L.r[i]=L.r[i-1]; for(j=i-2;LT(L.r[0].key,L.r[j].key);j--) L.r[j+1]=L.r[j]; L.r[j+1]=L.r[0]; } }
内部排序是指在排序过程中所有数据均放在内存中处 内部排序是指在排序过程中所有数据均放在内存中处 不需要使用外存的排序方法。 理,不需要使用外存的排序方法。而对于数据量很大 的文件,在内存不足的情况下,则还需要使用外存, 的文件,在内存不足的情况下,则还需要使用外存, 这种排序方法称为外部排序 这种排序方法称为外部排序 排序码相同的记录,若经过排序后, 排序码相同的记录,若经过排序后,这些记录仍保 持原来的相对次序不变,称这个排序算法是稳定的 稳定的。 持原来的相对次序不变,称这个排序算法是稳定的。 否则,称为不稳定的排序算法。 不稳定的排序算法 否则,称为不稳定的排序算法。
§10.3 快速排序
一、冒泡(起泡)排序 冒泡(起泡) 第1趟,对所有记录从左到右每相邻两个记录的排序码 进行比较,如果这两个记录的排序码不符合排序要求, 进行比较,如果这两个记录的排序码不符合排序要求, 则进行交换,这样一趟做完,将排序码最大者放在最 则进行交换,这样一趟做完, 后一个位置; 后一个位置; 趟对剩下的n 个待排序记录重复上述过程, 第2趟对剩下的n-l个待排序记录重复上述过程,又将 一个排序码放于最终位置,反复进行n 可将n 一个排序码放于最终位置,反复进行n-l次,可将n-l 个排序码对应的记录放至最终位置, 个排序码对应的记录放至最终位置,剩下的即为排序 码最小的记录,它在第1的位置处。 码最小的记录,它在第1的位置处。 如果在某一趟中,没有发生交换, 如果在某一趟中,没有发生交换,则说明此时所有记 录已经按排序要求排列完毕,排序结束。 录已经按排序要求排列完毕,排序结束。
设待排序的7 记录的排序码为{312, 126, 272, 226, 设待排序的 7 记录的排序码为 {312 , 126 , 272 , 226 , 28,165,123} 直接插入排序算法的执行过程如下: 28,165,123},直接插入排序算法的执行过程如下:
哨兵 排序码 [ ] 312,126,272,226,28,165,123 , , , , , , 初始 () i=2: (126) : ) i=3: (272) : ) i=4: (226) : ) i=5: (28) : ) i=6: (165) : ) i=7: (123) : ) [312],126,272,226,28,165,123 , , , , , , [126,312],272,226,28,165,123 , , , , , , [126,272,312],226,28,165,123 , , , , , , [126,226,272,312],28,165,123 , , , , , , [28,126,226,272,312],165,123 , , , , , , [28,126,165,226,272,312],123 , , , , , , [28,123,126,165,226,272,312] , , , , , ,
第10章 10章
§10.1 排序n个记录R 组成,所谓排 假设一个文件是由n个记录R1,R2,…,Rn组成,所谓排 就是以记录中某个(或几个)字段值不减(或不增) 序就是以记录中某个(或几个)字段值不减(或不增)的次 序将这n个记录重新排列,称该字段为排序码。 序将这n个记录重新排列,称该字段为排序码。关键字 可以作为排序码, 可以作为排序码,但排序码不一定要是关键字 按排序过程中使用到的存储介质来分, 按排序过程中使用到的存储介质来分,可以将排序分 成两大类:内部排序和外部排序 成两大类:
void ShellSort(SqList &L) d=L.length/2 { d=L.length/2; while(d>=1 while(d>=1) {for(i=d+1;i<=L.length;i++) /*保存第 个元素* 保存第i { L.r[0]=L.r[i]; /*保存第i个元素*/ j=i/*向前找插入位置 向前找插入位置* j=i-d; /*向前找插入位置*/ while(L.r[0 key<L.r[j].key&&j>0 while(L.r[0].key<L.r[j].key&&j>0) /* 找 插 入位置并后移* 入位置并后移*/ r[j+d]=L.r[j]; /*后移 后移* { L.r[j+d]=L.r[j]; /*后移*/ j=j/*继续向前查找 继续向前查找* j=j-d; /*继续向前查找*/ } r[j+d]=L.r[0 /*插入第 个元素的副本* 插入第i L.r[j+d]=L.r[0]; /*插入第i个元素的副本*/ } d=d/2 d=d/2; } }
10.2 插入排序
插入排序的基本方法是: 插入排序的基本方法是: 将待排序文件中的记录, 将待排序文件中的记录, 逐个地按其排序码值的大小 插入到目前已经排好序的若干个记录组成的文件中的适 当位置,并保持新文件有序。 当位置,并保持新文件有序。 一、直接插入排序 算法思路:初始可认为文件中的第1个记录己排好序, 算法思路:初始可认为文件中的第1个记录己排好序, 然后将第2个到第n 然后将第2个到第n个记录依次插入已排序的记录组成 的文件中。在对第i个记录Ri进行插入时:R Ri进行插入时 的文件中。在对第i个记录Ri进行插入时:R1,R2,…, 已排序,将记录R 的排序码key Ri-1已排序,将记录Ri的排序码keyi与已经排好序的排 序码从右向左依次比较,找到Ri应插入的位置,将该 序码从右向左依次比较,找到R 应插入的位置, 位置以后直到R 各记录顺序后移,空出该位置让R 位置以后直到Ri-1各记录顺序后移,空出该位置让Ri 插入
§10.4 选择排序
一、简单选择排序 先从所有n个待排序记录中选择排序码最小的记录, 先从所有n个待排序记录中选择排序码最小的记录,将 该记录与第1个记录交换,再从剩下的n 该记录与第1个记录交换,再从剩下的n-l个记录中选出 排序码最小的记录和第2个记录交换。 排序码最小的记录和第2个记录交换。重复这样的操作 直到剩下2个记录时, 直到剩下2个记录时,再从中选出排序码最小的记录和 个记录交换。剩下的那1 第n-1个记录交换。剩下的那1个记录肯定是排序码最大 的记录, 的记录,这样排序即告完成
二、希尔(Shell)排序 希尔(Shell)排序 (Shell) ——对有 个记录进行排序,首先取1个整数d<n 对有n d<n, ——对有n个记录进行排序,首先取1个整数d<n, 将这n个记录分成若干组,所有位置相差为d 将这n个记录分成若干组,所有位置相差为d的 倍数的记录分在同一组, 倍数的记录分在同一组,在每组中使用直接插 入排序进行组内排序,然后缩小d的值, 入排序进行组内排序,然后缩小d的值,重复进 行分组和组内排序,一直到d=1 d=1结束 行分组和组内排序,一直到d=1结束
二、快速排序 基本思路是: 基本思路是:从n个待排序的记录中任取一个记录(一般 个待排序的记录中任取一个记录( 取第1个记录) 取第1个记录),设法将该记录放置于排序后它最终应该 放的位置,使它前面的记录排序码都不大于它的排序码, 放的位置,使它前面的记录排序码都不大于它的排序码, 而后面的记录排序码都大于它的排序码,然后对前、 而后面的记录排序码都大于它的排序码,然后对前、后 两部分待排序记录重复上述过程, 两部分待排序记录重复上述过程,可以将所有记录放于 排序成功后的相应位置,排序即告完成。 排序成功后的相应位置,排序即告完成。 初始状态: 初始状态: 49 38 65 97 76 13 27 1次交换后:27 38 65 97 76 13 49 次交换后: 次交换后: 2次交换后:27 38 49 97 76 13 65 次交换后: 3次交换后:27 38 13 97 76 49 65 次交换后: 4次交换后:27 38 13 49 76 97 65 完成一趟排序: 完成一趟排序:27 38 13 49 76 97 65
{49,38,65,97,76,13,27,49} {49,38,65,97,76,13,27,49} 49 初始堆: 初始堆: 49 38 97 49 76 13 65 27 97 49 输出13, 97来代替13 输出13,用97来代替13 13 来代替 49 97 38 76 65 13 建堆: 建堆: 13 49 27 49 13 65 49 27