2012版《数据结构高分笔记》更新补丁之外部排序
排序之外部排序

排序之外部排序有时,待排序的⽂件很⼤,计算机内存不能容纳整个⽂件,这时候对⽂件就不能使⽤内部排序了(这⾥做⼀下说明,其实所有的排序都是在内存中做的,这⾥说的内部排序是指待排序的内容在内存中就可以完成,⽽外部排序是指待排序的内容不能在内存中⼀下⼦完成,它需要做内外存的内容交换),外部排序常采⽤的排序⽅法也是归并排序,这种归并⽅法由两个不同的阶段组成:1、采⽤适当的内部排序⽅法对输⼊⽂件的每个⽚段进⾏排序,将排好序的⽚段(成为归并段)写到外部存储器中(通常由⼀个可⽤的磁盘作为临时缓冲区),这样临时缓冲区中的每个归并段的内容是有序的。
2、利⽤归并算法,归并第⼀阶段⽣成的归并段,直到只剩下⼀个归并段为⽌。
例如要对外存中4500个记录进⾏归并,⽽内存⼤⼩只能容纳750个记录,在第⼀阶段,我们可以每次读取750个记录进⾏排序,这样可以分六次读取,进⾏排序,可以得到六个有序的归并段,如下图:每个归并段的⼤⼩是750个记录,记住,这些归并段已经全部写到临时缓冲区(由⼀个可⽤的磁盘充当)内了,这是第⼀步的排序结果。
完成第⼆步该怎么做呢?这时候归并算法就有⽤处了,算法描述如下:1、将内存空间划分为三份,每份⼤⼩250个记录,其中两个⽤作输⼊缓冲区,另外⼀个⽤作输出缓冲区。
⾸先对Segment_1和Segment_2进⾏归并,先从每个归并段中读取250个记录到输⼊缓冲区,对其归并,归并结果放到输出缓冲区,当输出缓冲区满后,将其写道临时缓冲区内,如果某个输⼊缓冲区空了,则从相应的归并段中再读取250个记录进⾏继续归并,反复以上步骤,直⾄Segment_1和Segment_2全都排好序,形成⼀个⼤⼩为1500的记录,然后对Segment_3和Segment_4、Segment_5和Segment_6进⾏同样的操作。
2、对归并好的⼤⼩为1500的记录进⾏如同步骤1⼀样的操作,进⾏继续排序,直⾄最后形成⼤⼩为4500的归并段,⾄此,排序结束。
外部排序处理大规模数据的外部存储排序算法

外部排序处理大规模数据的外部存储排序算法在计算机科学中,外部排序是指对大规模数据进行排序时所采用的一种排序方式。
由于计算机内存的有限性,当数据量超过内存容量时,无法一次性加载到内存中进行排序。
因此,我们需要将数据分割成多个较小的块,在磁盘上进行排序,然后再将排序好的块逐个合并成最终有序的结果。
外部存储排序算法是一种用于处理大规模数据的高效排序算法,它充分利用了磁盘I/O的特性,以提高排序的效率和整体性能。
下面将介绍两种常见的外部存储排序算法:归并排序和多路归并排序。
一、归并排序归并排序是一种常见的排序算法,它也被广泛应用于外部存储排序中。
其基本思想是将待排序的数据划分为若干个子序列,分别进行内部排序,然后再将排好序的子序列进行合并,最终得到全局有序的结果。
归并排序的具体步骤如下:1. 将大规模数据划分成多个块并加载到内存中。
2. 对每个块进行内部排序,可以选择快速排序、堆排序等高效的排序算法。
3. 将排好序的块写入磁盘,同时将下一块数据加载到内存中。
4. 重复步骤2和步骤3,直到所有块都排序完毕。
5. 对排好序的块进行多路归并,生成最终的有序结果。
归并排序的时间复杂度为O(n log n),其中n表示待排序数据的总量。
它的优势在于适用于处理大规模数据,但由于需要频繁进行磁盘I/O,因此效率较低。
二、多路归并排序多路归并排序是一种改进版的归并排序算法,它能够同时合并多个有序的子序列,并生成一个更大的有序序列。
与传统的两路归并排序不同,多路归并排序可以合并超过两个的子序列。
多路归并排序的核心思想是使用最小堆来管理各个子序列的当前元素,每次从堆中选择最小的元素输出,并将其所在的子序列的下一个元素加入堆中。
通过不断地选择最小的元素,最终实现多路归并排序。
多路归并排序的具体步骤如下:1. 将大规模数据划分成多个块并加载到内存中。
2. 对每个块进行内部排序,可以选择快速排序、堆排序等高效的排序算法。
3. 将块的首个元素创建最小堆,并将最小堆中的元素输出到磁盘。
数据结构-C语言描述(第二版)课件:外部排序

外部排序
磁盘的存取时间主要取决于寻查时间和等待时间。 磁 盘以2400~3600 r/min的速度旋转,因此平均等待时间约为 10 ms~20 ms, 而平均寻查时间约为几毫秒至几十毫秒,这 与CPU的处理速度相比较而言,仍是很慢的。因此,在讨论 外存的数据结构及其上的操作时,要尽量设法减少访问外存 的次数, 以提高磁盘存取效率。
第四步:把T1上的顺串1和T3上的顺串3合并,并把结 果放到T2
外部排序
上述例子采用的是2路归并法,与磁盘排序的情况一样, 排序的时间主要取决于对数据的扫描遍数。采用多路归并 能减少扫描的遍数,但对磁带排序来说,多路归并需要多 台磁带机,为了避免过多的磁带寻找时间,要归并的顺串 需要放在不同的磁带上。因此,k路归并至少需要k+1台磁 带机,其中k台作为输入带,另外一台用于归并后存放输出 结果。但这样需要对输出带再作一遍扫描,把输出带上的 各顺串重新分配到k台磁带上,以便作为下一级归并 使用。若使用2k台磁带机,则可避免这种再分配扫描,把k 台作为输入带,其余k台作为输出带,在下一级归并时,输 入带与输出带的作用互相对换。上述例子就是用4台磁带机 实现2路归并,T1、T2和T3、T4轮流地用作输入带和输出带。
外部排序 图10.2 活动臂示意图
外部排序
活动臂磁盘的磁头是安装在一个可活动臂上,随着活动 臂的移动, 磁头可在盘面上做同步的径向移动,从一个磁道 移到另一个磁道, 当盘面高速旋转,磁道在读/写头下通过 时,便可进行信息的读写。各记录盘面上半径相同的磁道合 在一起称为一个柱面, 柱面上各磁道在同一磁头位置下,即 活动臂移动时,实际上是把这些磁头从一个柱面移到另一个 柱面。 一个磁道内还可以分为若干段,称为扇段。因此,对 磁盘存储来说,由大到小的存储单位是: 盘片组,柱面,磁 道,扇段。以IBM2314型磁盘为例,其参数为:20个记录面 /磁盘组,200个磁道/记录面,7294字节/磁道。因此, 整个盘片组的容量为: 7294×200×200≈29 MB。
外部排序1-2

子序列为 “归并段”;
2.通过“归并”,逐步扩大(记录的)有序子序列
的长度,直至外存中整个记录序列按关键字有序为
止。
10
11.2
外部排序的方法
例如:假设有一个含10,000个记录的磁盘文件,而 当前所用的计算机一次只能对1,000个记录进行内 部排序,则首先利用内部排序的方法得到10个初始 归并段,然后进行逐趟归并。
一般情况下,假设待排记录序列含 m 个初始归并段,外排时 采用 k路归并,则归并趟数s=logkm,显然,随着k的增 大或m的减小,归并的趟数将减少,因此对外排而言,通常采 用多路归并。k 的大小可选,但需综合考虑各种因素。
14
11.3
多路平衡归并的实现
一、多路平衡归并的性质: •分析: m 个初始归并段,外排时采用 k路归并,则归 并趟数为 logkm , K 大,趟数减少,读写记录的总 数将减少。但 K 大,会使内部归并时间tmg增大?。
20
11.3 多路平衡归并的实现
三、败者树及其使用
ls [0]
0 ls[1] 3 ls[2] 0 5 ls[3] 1 9 2 7 3 29 4 5 5 7 6 29 7 9
4路平衡归并
1
b[1] 5 输 入
5 16 49 52 78
2
b[2] 29
29 38 57 66 71
b[0]
b[3] 9 注意:挑出冠军
二、胜者树及其使用
1
9 1 9 2 12 3 9 2 12 3 9 4 16 5 12 6 29 7 9
4路平衡归并
4 16 输 入
5 16 49 52 78
5 12
7 12 25 84 91
6 29
第十一章 外部排序

2
b1 9 9 18 20 . b2 20
3 4
b4 12 12 37 48 .
10
10 15 16 .
20 22 40 .ຫໍສະໝຸດ §11.4 置换-选择排序
• 问题: 是否可以不用内部排序构造初始归并段? • 例:若初始文件含有24个记录,其的关键字为: 51,49,39,46,38,29,14,61,15,1,48,52, 3,63,27,4,1389,24,46,58,33,76。 假设内存工作区可容纳6个记录,则可得如下4个初始 归并段: • RUN1:29,38,39,46,49,51 • RUN2:1,14,15,30,48,61 • RUN3:3,4,13,27,52,63 • RUN4:24,33,46,58,76,89
§11.3 多路平衡归并的实现
• 例:
3 1
胜利者
失败者
0
b0 b3 6 6 15 25
.
2
b1 9 9 18 20 . b2 20
4
b4 12 12 37 48 .
10
10 15 16 .
20 22 40 .
§11.3 多路平衡归并的实现
• 例:
1 3 0 1
胜利者
失败者
4 0
b0 b3 15 15 25
15,30,1,48,52,3,63,27,4,… 30,1,48,52,3,63,27,4,…
30,1,48,52,3,63,27,4,… 1,48,52,3,63,27,4,… 48,52,3,63,27,4,… 52,3,63,27,4,…
FO
29,38,39,46,49,51,61
WA
48,1,15,30,52,14 3,63,27,4,…
数据结构--排序算法介绍

数据结构--排序算法总结概述排序的分类:内部排序和外部排序内部排序:数据记录在内存中进行排序外部排序:因排序的数据量大,需要内存和外存结合使用进行排序这里总结的八大排序是属于内部排序:当n比较大的时候,应采用时间复杂度为(nlog2n)的排序算法:快速排序、堆排序或归并排序。
其中,快速排序是目前基于比较的内部排序中被认为最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短。
———————————————————————————————————————————————————————————————————————插入排序——直接插入排序(Straight Insertion Sort)基本思想:将一个记录插入到已排序好的有序表中,从而得到一个新的,记录数增1的有序表。
即:先将序列的第1个记录看成一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。
要点:设立哨兵,用于临时存储和判断数组边界直接插入排序示例:插入排序是稳定的,因为如果一个带插入的元素和已插入元素相等,那么待插入元素将放在相等元素的后边,所以,相等元素的前后顺序没有改变。
算法实现:[cpp]view plain copy1.#include<iostream>ing namespace std;3.4.void print(int a[], int n ,int i)5.{6. cout<<i<<":";7.for(int j= 0; j<8; j++){8. cout<<a[j] <<" ";9. }10. cout<<endl;11.}12.13.void InsertSort(int a[],int n)14.{15.int i,j,tmp;16.for(i=1;i<n;++i)17. {18.// 如果第i个元素大于第i-1个元素,直接插入19.// 否则20.// 小于的话,移动有序表后插入21.if(a[i]<a[i-1])22. {23. j=i-1;24. tmp=a[i]; // 复制哨兵,即存储待排序元素25. a[i]=a[i-1]; // 先后移一个元素26.while(tmp<a[j])27. {28.// 哨兵元素比插入点元素小,后移一个元素29. a[j+1]=a[j];30. --j;31. }32. a[j+1]=tmp; // 插入到正确的位置33. }34. print(a,n,i); // 打印每一趟排序的结果35. }36.}37.38.int main()39.{40.int a[8]={3,1,5,7,3,4,8,2};41. print(a,8,0); // 打印原始序列42. InsertSort(a,8);43.return 0;44.}分析:时间复杂度:O(n^2)———————————————————————————————————————————————————————————————————————插入排序——希尔排序(Shell Sort)基本思想:先将整个待排序的记录序列分割成为若干子序列,分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录依次进行直接插入排序。
外部排序技术之多路归并

外部排序技术之多路归并外部排序技术之多路归并重点:败者树的创建调整函数1.外部排序概述外部排序指的是⼤⽂件的排序,即待排序的记录存储在外存储器上,待排序的⽂件⽆法⼀次装⼊内存,需要在内存和外部存储器之间进⾏多次数据交换,以达到排序整个⽂件的⽬的。
外部排序最常⽤的算法是多路归并排序,即将原⽂件分解成多个能够⼀次性装⼈内存的部分,分别把每⼀部分调⼊内存完成排序。
然后,对已经排序的⼦⽂件进⾏归并排序。
2. 多路归并的实现2.1 胜者树胜者进⼊下⼀轮,直⾄决出本次⽐赛的冠军。
决出冠军之后,充分利⽤上⼀次⽐赛的结果,使得更快地挑出亚军、第三名 …… 。
⽰例:我们这⾥以四路归并为例,假设每个归并段已经在输⼊缓冲区如下图。
每路的第⼀个元素为胜利树的叶⼦节点,(5,7)⽐较出5胜出成为其根节点,(29,9)⽐较9胜出成为其根节点,⼀次向上⽣成⼀棵胜利树,然后我们可以得出5为冠军,将第⼀路归并段的元素5放⼊输出缓冲区,然后将第⼀路第⼆个元素放到胜利树中如下:由第⼀次得到的胜利树知,我们这⾥只改变了第1路的叶⼦节点,所有根节点7的右⼦树不⽤再⽐较,(16,7)⽐较7胜出,然后7和右⼦树的胜利者⽐较7胜出得到亚军,只进⾏了2次⽐较。
所以我们知道:决出第⼀名需⽐较: k - 1 次决出第⼆名需⽐较:次决出第三名需⽐较:次 .............2.2 败者树与胜利树相类似,败者树是在双亲节点中记录下刚刚进⾏完的这场⽐赛的败者,让胜者去参加更⾼⼀层的⽐赛。
⽰例:我们这⾥以四路归并为例,假设每个归并段已经在输⼊缓冲区如下图。
每路的第⼀个元素为胜利树的叶⼦节点,(5,7)⽐较出5胜出7失败成为其根节点,(29,9)⽐较9胜出29失败成为其根节点,胜者(5,9)进⾏下次的⽐赛7失败成为其根节点5胜出输出到输出缓冲区。
由第⼀路归并段输出,所有将第⼀路归并段的第⼆个元素加到叶⼦节点如下图:加⼊叶⼦节点16进⾏第⼆次的⽐较,跟胜利树⼀样,由于右⼦树叶⼦节点没有发⽣变化其右⼦树不⽤再继续⽐较。
数据结构之排序算法详解(含代码)

C/C++版数据结构之排序算法今天讨论下数据结构中的排序算法。
排序算法的相关知识:(1)排序的概念:所谓排序就是要整理文件中的记录,使之按关键字递增(或者递减)次序罗列起来。
(2)稳定的排序方法:在待排序的文件中,若存在多个关键字相同的记录,经过排序后这些具有相同关键字的记录之间的相对次序保持不变,该排序方法是稳定的。
相反,如果发生改变,这种排序方法不稳定。
(3)排序算法的分类(分为5类):插入排序、选择排序、交换排序、归并排序和分配排序。
(4)排序算法两个基本操作:<1>比较关键字的大小。
<2>改变指向记录的指针或者挪移记录本身。
具体的排序方法:插入排序<1>插入排序(Insertion Sort)的思想:每次将一个待排序的记录按其关键字大小插入到前面已经排好序的子记录中的适当位置,直到全部记录插入完成为止。
<2>常用的插入排序方法有直接插入排序和希尔排序。
(1)直接插入排序<1>算法思路:把一个记录集(如一个数组)分成两部份,前半部份是有序区,后半部份是无序区;有序区一开始有一个元素r[0],无序区一开始是从r[1]到之后的所有元素;然后每次从无序区按顺序取一个元素r[i],拿到有序区中由后往前进行比较,每次比较时,有序区中比r[i]大的元素就往后挪移一位,直到找到小于r[i]的元素,这时r[i]插到小元素的后面,则完成一趟直接插入排序。
如此反复,从无序区不断取元素插入到有序区,直到无序区为空,则插入算法结束。
<2>算法演示://直接插入排序:#include<iostream>using namespace std;void InsertSort(int r[],int n);int main(){int r[]={24,1,56,2,14,58,15,89};InsertSort(r,8);for(int i=0;i<8;i++){cout<<r[i]<<' ';}cout<<endl;return0;}void InsertSort(int r[],int n){for(int i=1;i<n;i++){for(int j=i-1,s=r[i];s<r[j] && j>=0;j--){r[j+1]=r[j];}r[j+1]=s;}}复制代码(2)折半插入排序<1>算法思路:我们看到在直接插入排序算法中,需要在有序区查找比r[i]的小的元素,然后插入到这个元素后面,但这里要注意这个元素是从无序区算第一个比r[i]小的元素。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
※特别章外部排序(2012版《数据结构高分笔记》更新补丁)
·外部排序简介
所谓外部排序,即对外存中的数据进行排序(相对于内部排序而言),也可以说是对文件中的数据进行排序。
有了内部排序算法,为什么还要外部排序?因为文件太大,内存放不下。
外排做法可以概括为一句话:将内存作为工作空间来调整外存中数据的位置。
具体可以分成以下三个要点:
①文件在外存中的组织;
②文件在内存中的排序;
③文件在内外存之间的交换。
说明:本补丁是2012年数据结构考研大纲新增内容,虽然知识点不多,但由于第一年被列入考试范围,所以大家要重视。
·归并排序法
归并排序法是外排序中最常用的方法,分为两个执行阶段。
第一阶段:将文件中的数据分段输入到内存中,在内存中用内排序方法对其分类,这样排序完的文件段称作归并段,然后将其写回外存中而在外存中形成了许多初始归并段。
第二阶段:对这些初始归并段采用某种归并方法,进行多遍归并,最后在外存上形成整个文件的单一归并段,也就完成了这个文件的外排序。
说明:外排序中的归并排序法和内排序中的归并法是类似的,都是由小单元逐渐归并成单元的过程,注意对比,加深理解。
归并排序算法分两个阶段:
1.初始归并段的形成
其过程是根据缓冲区大小,由文件输入(由外存读入内存)记录,当记录充满缓冲区后,选择最小的(以递增排序为例)记录输出(由内存写出到外存),其空缺位置由下一个输入记录来取代,输出的记录成为当前初始归并段的一部分。
如果新输入的记录不能成为当前生成的归并段的一部分,即它比生成的当前部分归并段最大的记录要小(如例1中的关键字11,比15要小,不可能出现在当前归并段中),它将等待生成下一个归并段时提供选择。
反复进行上述操作,直到所有新输入的记录关键字都小于最后输出记录的关键字时(如步骤9中的所有关键字都比83小,则以83为结尾的归并段生成完毕),就生成了一个初始归并段。
接着继续生成下一个归并段,直到全部记录都处理完毕为止。
下面通过例题来具体说明一下。
例1.设输入文件的各个记录的关键字为:
15,19,04,83,12,27,11,25,16,34,26,07,10,90,06, ... ...
假设内存缓冲区可容纳4个记录,成初始归并段。
如下表所示,给出了生成初始归并段过程中各步的缓冲区内容和输出结果。
步
数
1 2 3 4 5 6 7 8 9 10 11 12 13 ...
缓冲区内容15 15 15 11 1111111111 11 11 06 ......
19 19 19 19 25161616
16 16 16 16 ......
04 12 27 27 2727342626 26 26 26 ......
83 83 83 83 8383838307 10 90 90 ......
输出结果
04 12 15 19 25 27 34 83 07 10 11 06 ... ...
所生成的第一初始归并段所生成的第二初始归并段
... ...
初始归并段生成过程表(表中下划线数字即为生成下一归并段的候选数字)
2. k路归并
有了m个初始归并段(都是有序段),便可以进行k路归并了,即将k个初始归并段
归并产生一段,这样,m个初始归并段产生多个这样的段,然后对这些段再用同样的方法进行归并,如此往复,直到归并成一个段为止,这个段就是最后生成的归并段。
例2.一个文件,含有10000个记录,通过1.1中介绍的方法,得到10个初始归并段R1... R10,其中每一个段都含有1000个记录。
外存上的信息读/写是以物理块为单位进行的,假设每个物理块可以容纳200个记录,则每一趟归并需要进行50次读和50次写,4趟归并加上内部排序所需要进行的读/写使得在外排序中总共需要进行500次读/写。
对初始归并段做两两归并:
R1,R2 R3,R4 R5,R6 R7,R8 R9,R10 R1’ R2’ R3’ R4’ R5’
R1” R2” R3”
R1’’’ R2’’’
R1’’’’(有序文件)
每次都由m个归并段得到个归并段,这种归并方法称为2-路归并。
若对上例进行5-路归并则有:
R1,R2,R3,R4,R5 R6,R7,R8,R9,R10
R1” R2”
R1’’’(有序文件)
·归并排序时间复杂度分析
m个初始归并段进行k路归并,归并的遍数为。
为
理的时间,而归并遍数为,所。
图1
(2)第一次比较胜出者5与第三个叶子结点10比较,10为败者,5为胜者,因而10替换到5的位置,5作为胜者向上一级比较,如图2
图2
(3)同理,依次比较其他各叶子结点,最终得到第一棵败者树为:
图3
K路归并的败者树的深度⎡log2k⎤在每次调整查找下一个具有最小关键字记录时,最多做⎡log2k⎤次关键字比较。
因此,利用败者树在K个记录中选择最小者,时间复杂度为O(log2k)。
说明:败者树和其他选择树的原理都是一样的,比如之前堆排序中的堆。
做法都是先用一个较大的时间复杂度将待排元素建成一棵满足一定要求的树,然后就可以从中取出一个满足要求的元素,并将新来的元素放在刚取出元素的位置上;这样只会在一点上对树的结构造成破坏而不会造成全局的破坏,因此只需花较小的时间复杂度进行局部调整即可将被破坏的结构恢复正常,无需从新建树。
局部调整即可恢复结构从而降低时间复杂度,这就是选择树的精髓。
数据结构就是这样,其实各种乱七八糟的结构都是表象,浮云,其背后的本质就那么一点,懂了这个之后,数据结构学习就会很轻松,最后祝大家考研愉快。
习题心选:
一、选择题:
1.外排序是指()
A.在外存上进行的排序方法。
B.不需要使用内存的排序方法。
C.数据量大,需要人工干预的排序方法。
D.排序前后数据在外存,排序时数据调入内存的排序方法。
2.文件有m个初始归并段,采用k路归并时,所需的归并遍数是()
A.log2k
B.log2m
C.log k
m D.
1 2 3 4 5 6 7 8 9 10 11
缓冲区内容10 12 13 21 21 21 16 16 16 16 20 20 20 20 20 8 8 8
15 15 15 15 30 30 30 30
25 25 25 25 25 25 25 10 10
输出结果10 12 13 15 20 21 25 30 8 10 16
第一初始归并段第二初始归并段
本题简单,每次从缓冲区中选出最小且比当前归并段最大的元素还要大的输出,空出来的位置读入新的关键字(参照例1 解法)。
2.答:内部排序中的归并排序是在内存中进行的归并排序,辅助空间为O(n)。
外部归并排序是将外存中的多个有序子文件合并成一个有序子文件,将每个子文件中记录读入内存后的排序方法可采用多种内排序方法。
外部排序的效率主要取决于读写外存的次数,即归并的趟数。
因为归并的趟数s=⎡log k m⎤,其中,m是归并段个数,k是归并路数。
增大k和减少m 都可减少归并趟数。
应用中通过败者树进行多(k)路平衡归并和置换-选择排序减少m,来提高外部排序的效率。