收藏 分享(赏)

10 内部排序.ppt

上传人:Facebook 文档编号:8896156 上传时间:2019-07-16 格式:PPT 页数:74 大小:1.19MB
下载 相关 举报
10 内部排序.ppt_第1页
第1页 / 共74页
10 内部排序.ppt_第2页
第2页 / 共74页
10 内部排序.ppt_第3页
第3页 / 共74页
10 内部排序.ppt_第4页
第4页 / 共74页
10 内部排序.ppt_第5页
第5页 / 共74页
点击查看更多>>
资源描述

1、第10章 内部排序,10.1 概述 10.2 插入排序 10.3 快速排序 10.4 选择排序 10.5 归并排序 10.6 基数排序 10.7 各种内部排序方法的比较讨论,排序就是将一组杂乱无章的数据按一定的规律顺次排列起来。 排序的目的是为了方便以后的查找。,10.1 概述,排序(Sorting):简单地说,就是将一组记录按关键字域递增(由小到大)或递减(由大到小)的次序重新排列。 排序码(Sort Key):作为排序依据的关键字。,有序表:排序后的结果。无序表:排序前的状态。,升序表正序表:按排序码升序排列的有序表。降序表逆序表:按排序码降序排列的有序表。,一、概念:,稳定排序:键值相同

2、的记录,排序后相对次序总能保持不变。 不稳定排序:键值相同记录排序前后相对次序不能保持不变。,待排序列: 49,38,65,97,76,13,27,49 排序后:13,27,38,49,49,65,76,97 稳定 排序后:13,27,38,49,49,65,76,97不稳定,内排序:排序过程全部在内存中进行。 外排序:排序过程需要进行内存和外存之间的数据交换。,内排序,插入排序(直插排序、二分排序、希尔排序) 交换排序(冒泡排序、快速排序) 选择排序 (直选排序、树型排序、堆排序) 归并排序(二路归并排序、多路归并排序) 分配排序 (多关键字排序、基数排序),无序区,有序区增长法:排序表可分

3、成有序区和无序区,随着排序过程的进行,有序区逐渐增长,无序区逐渐缩小,最后全部为有序区,排序结束。初始有序区可为空或仅含一个元素,其余为无序区。,一趟排序,有序区,有序区,无序区,有序度增长法:排序表不能分成明显的有序区和无序区,但排序过程的每一步,整个排序表的有序程度都提高一点,最后变得完全有序。,评价标准: 1)时间; 2)附加空间。 3)算法的稳定性、复杂程度等附加空间一般不大,排序经常执行,时间开销是最重标志。两种基本操作: 1)比较:比较关键字的大小 2)移动:将记录从一个位置移动到另一个位置。时间开销主要指关键字的比较次数和记录的移动次数。当键值是字串时,比较要占用较多的时间;当记

4、录很大时,交换记录时移动要占较多时间。比较一般都需要,但移动可改变存储方式来避免。,二、时空分析:,1)顺序存储。对记录本身进行物理重排,移到合适的位置。 2)链式存储。无需移动记录,仅修改指针。(链)表排序。 3)索引顺序存储。对索引表物理重排,不移动原始记录本身。,三、存储方式,const int maxsize=100; /排序表容量,假设为100 typedef int datatype; /假设关键字为int typedef struct datatype key; /关键字域othertype other; /其它域 rectype; /记录类型 typedef rectype l

5、istmaxsize+1;/排序表类型,0号单元不用(或作它用,如“监视哨”),为简单起见,本章以数组作存储结构:,10.2 插入排序,基本思想依次将待排记录插入到有序区适当位置,直到全部记录插入完毕;初始有序区只有一个元素。,一、基本思想,每次将无序区第1条记录插入到有序区适当位置。初始取第1条记录为有序区,其它记录为无序区。随着排序进行,有序区不断扩大,无序区不断缩小。最终无序区为空,有序区包含了全部记录,排序结束。有序区也可从排序表的尾部生成 。,10.2.1 直接插入排序 (Straight Insertion Sort),例1:对(49 38 13 76 65 97 27 49 )直

6、接插入排序。初始:(49)38 13 76 27 49,(13 38 49 49 65 97),(13 27 38 49 65 )49,(13 38 49 76)27 49,(13 38 49 )76 27 49,(38 49)13 76 27 49,为提高插入时的查找 效率,可以采用 折半查找 称为 折半插入排序,void InsertSort(list R,int n) /无监视哨int i,j; NODE x; /x为中间结点变量for(i=2;i=Ri-1.key) continue;x=Ri; /把待排记录赋给 xj=i-1;do /顺序比较和移动Rj+1=Rj;j-; while(

7、j0 /插入Ri ,二、算法实现,无序区第一记录Ri 插入有序区R1Ri1,找插入位置和移动记录交替进行:从有序区的后部j开始,如果该位置记录大于待插记录,则后移一位;待插记录插入到最后空出的位置上。,void InsertSort(list R,int n) /有监视哨int i,j;for(i=2;i=Ri-1.key) continue;R0=Ri; /R0是监视哨j=i-1;do /顺序比较和移动Rj+1=Rj;j-; while(R0.keyRj.key); Rj+1=R0; /插入Ri ,R0为监视哨(Sentinel),省略下标越界检查“j0”:一旦越界,j=01,循环条件R0.

8、keyRj.key不成立,自动控制while循环的结束。,初始:,i=3:,j=2:,j=1:,j=0:,例 有监视哨,第3趟,三、效率分析,时间:最好:正序,n-1趟插入,每趟比较1次,移动0次:Cmin=n-1=O(n),Mmin=0 最坏:逆序,每趟比较i-1次,移动i-1+2次。平均: O(n2) 空间:一个辅助空间,用于交换(或监视哨) 。 稳定:相邻元素比较和移动 可用于链表 适用于基本(正向)有序或n较少的情况,一、基本思想,排序表分成若干组,相隔为某个“增量”的记录为一组,各组内直接插入排序;初始增量d1较大,分组较多(每组的记录数少),以后增量逐渐减少,分组减少(每组的记录数

9、增多),直到最后增量为1(d1d2dt=1),所有记录放为同一组,再整体进行一次直接插入排序。 又称“缩小增量排序”(Diminishing Increment Sort) 。,10.2.2 希尔排序,例如,对(49,38,65,97,76,13,27,49)希尔排序。,初始关键字,d1=5,例如,对(49,38,65,97,76,13,27,49)希尔排序。,8,7,6,5,4,3,2,1,一趟排序结果,d1=3,例如,对(49,38,65,97,76,13,27,49)希尔排序。,8,7,6,5,4,3,2,1,二趟排序结果,d1=1,例如,对(49,38,65,97,76,13,27,4

10、9)希尔排序。,一趟排序结果,二趟排序结果,三趟排序结果,初始关键字,二、算法实现,void ShellInsert(list R,int n,int h) /一趟插入排序,h为本趟增量int i,j,k;for(i=1;i=Rjh.key) continue;R0=Rj; /R0保存待插记录,但不是监视哨k=jh; /待插记录的前一个记录do /查找插入位置Rk+h=Rk;k=kh;/后移记录,继续向前搜索 while(k0 /插入Rj ,两个for循环可合并为一个:for(j=1+h;j=n;j+),相当于对每组交替直接插入排序。,void ShellSort(list R,int n,i

11、nt d,int t) /d为增量序列,t为增量序列长度int i;for(i=0;it;i+) /各趟插入排序ShellInsert(R,n,di); ,希尔排序就是调用若干趟插入排序:,三、效率分析,时间:O(nlog2n)和O(n2)之间,大致O(n1.3) ,优于直接插入 其一,加速原理。相隔为增量的记录一组,组内移动一位,对原序列则移动若干位,加速向目标位置移动。开始时无序程度大,增量大,加速快;以后每个增量排序后,有序度提高一些,增量缩小,加速减缓。 其二,基本有序和小规模原理。开始时增量大,分组多,组内记录少,组内直接插入快;后来增量缩小,分组少,组内记录多,但有序性提高了,排序

12、也较快。 不稳定:组内“相邻”移动,原序列则跳跃移动,10.3 交换排序,基本思想: 每次比较两个待排序的记录,如果关键字的次序与排序要求相反时就交换两者的位置,直到没有反序的记录为止。 特点: 键值较大的记录向排序表的一端移动,键值较小的记录向另一端移动。,一、基本思想,设排序表垂直放置,每个记录看作重量为键值的气泡;根据轻上重下原则,从下往上扫描,违反本原则的轻气泡,向上“飘浮”,如此反复,直到任何两个气泡都是轻上重下为止。每一趟一个“最轻”的气泡冒到顶部上升法。 也可从上向下扫描,这时每一趟是一个“最重”的气泡沉到底部下沉法。 每次交换时,其中一个总沿着最终方向,另一个则未必(取决于上升

13、法还是下降法)。,起泡排序(Bubble Sort),例:对(49,38,65,97,76,13,27,49)冒泡排序。,void BubbleSort(list R,int n) /上升法冒泡排序int i,j,flag;for(i=1;i=i+1;j) /从下向上扫描if(Rj.keyRj1.key) /交换记录flag=1;R0=Rj;Rj=Rj1;Rj1=R0;/交换,R0作辅助量 if(!flag) break; /本趟未交换过,排序结束 ,二、算法实现,排序中各元素不断接近自己的位置,如果一趟下来没有交换,则序列已经有序,可设一个标志flag判断,提前结束。,时间: 最好:初始正序

14、,一趟排序,比较n-1次,移动0:Cmin=n-1=O(n),Mmin=0: 最坏:初始逆序,n-1趟排序,每趟比较ni次,每次比较3次移动:平均: O(n2) 辅助空间1,用于交换(用R0代替)。 稳定:只对相邻记录顺序比较和交换。 可用于链表(下沉法),三、效率分析,例 链表起泡排序下沉法,15,35,25,h,45,q,p,15,35,h,25,45,end,end,h,15,25,35,45,end,NULL,搜索结束条件:p-next=end end初值为NULL,以后指向每趟最后点。,一、基本思想,任选一记录作基准,其它记录与之比较,小于等于放基准前面;大于等于放基准后面。 一趟排

15、序后,左子序列小于等于基准,右子序列大于等于基准。对两子序列进行同样处理,直至每组只有1个记录,全部记录有序。又称划分交换排序 可看成冒泡排序的改进:记录的比较和交换从两端向中间进行,较大的记录每次交换到较后位置,较小的交换到较前位置,每次移动距离较远,总的比较和移动次数较少。 是目前为止所有内排序中速度最快的一种。,快速排序(Quick Sorting),1)一趟划分:,二、算法实现,设划分区间RpRq,指针i、j分别指向p、q。第1记录作基准j从右向左扫描,找1个小于基准的记录Rj,移到位置i; i自i+1起从左向右扫描,找1个大于基准的记录Ri,移到位置j 再令j自j1起向左扫描,如此交

16、替改变扫描方向,从两端往中间靠拢,直至i=j时,i便是基准的最终位置,将它放在该处。,一 趟 划 分,初始关键字,49,49,初始关键字,例,对(49,38,65,97,76,13,27,49)快速排序,快速排序的判定树: 树根表示基准,左右子树表示划分的两个区间,每个子区间继续用子二叉树表示。,int Partition(list R,int p,int q) /对无序区Rp到Rq划分,返回划分后基准的位置int i,j;i=p; j=q; R0=Ri;/R0作辅助量,存基准(无序区第一个记录)while(i=R0.key ,基准在扫描中不必真正交换,划分完成得到最终位置后再放入,void

17、QuickSort(list R,int s,int t) /对Rs到Rt快速排序int i;if(s=t) return; /只有一个记录或无记录无需排序i=Partition(R,s,t); /对Rs到Rt做划分QuickSort(R,s,i1); /递归处理左区间QuickSort(R,i+1,t); /递归处理右区间 ,2)快速排序算法,设排序区间为Rs到Rt,一趟划分后得到基准位置i,接着对区间Rs到Ri1、Ri+1到Rt进行递归处理。,对整个排序表R进行快速排序,调用QuickSort(R,1,n);,时间: 最好:每次划分两侧大致相等,判定树高log2n1 ,Cmin n(log

18、2n+1)=O(nlog2n) 最坏:每次划分一侧空,剩下另一侧,判定树为单枝树,蜕化为冒泡排序 :移动次数不大于比较的次数 平均: O(n log2n) 辅助空间为栈,深度最好O (log2n),最坏O(n) 。 不稳定:两头比较和交换,可改变相同键值记录的相对位置,三、效率分析,10.4 选择排序 (Selection Sort),基本思想 每一趟从待排记录中选关键字最小(或最大)的记录,顺序放在已排序的子序列的最后(或最前),直到全部记录排完,一、基本思想,所有记录组成初始无序区,每趟都从无序区中选出键值最小的记录,与无序区第一个记录交换,有序区增加了一个记录。n1趟排序后,整个排序表就

19、全部有序了。可看成冒泡排序:比较和交换的是无序区最小和无序区第一个,不是相邻两个。总比较次数相同,但移动次数少。,10.4.1 简单选择排序 (Straight Selection Sort),例,对(49,38,65,97,76,13,27,49)简单选择排序,void SelectSort(list R,int n) int i,j,k;for(i=1;i=n1;i+) /n1趟排序k=i;for(j=i+1;j=n;j+) /无序区中找最小Rkif(Rj.keyRk.key) k=j;if(k!=i) R0=Ri;Ri=Rk;Rk=R0;/交换Ri和Rk,R0作辅助 ,二、算法实现,三、

20、效率分析,时间:n1趟,每趟都找最小,总比较次数:最好:初始正序,无移动,Mmin0,Cmin=O(n2) 最坏:初始反序,Mmax3(n-1) ,Cmax=O(n2) 平均:O(n2) 辅助空间1,用于交换 不稳定:有不相邻记录交换 可用于链表,15,25,25,15 ,例 链表选择排序,25,35,15,f,h,25,f,15 ,h,35 ,f,35 ,h,f,h,35 ,NULL,NULL,每次找一个最大,头插入新链表,也可每次找一个最小,尾插入新链表,直接选择排序时,从n个键值中找最小比较n1次,剩下的找次小比较n2次,再找第三小比较n3次,总比较次数为: (n1)+(n2)+3+2+

21、1= n(n1)/2,10.4.2 树形选择排序 Tree Selection Sort,实际上,除第一次的n1次比较外,后面各次比较中很多在前面已经做过,但结果没有保留,所以在以后又重复进行。,n个记录两两比较,得到 n/2 个较小者。然后再两两比较。如此重复,直至选出键值最小的记录为止。如果某组只有一个记录,则轮空,直接进入下一轮比较。 这个过程可用一棵完全二叉树来表示,故称树形选择排序 该过程又象锦标赛,两两决胜负,最后决出冠军,故又称锦标赛排序(Tournament Sort)。,49,13,13,65,97,39,38,13,38,38,65,76,13,27,27,例:对(49 3

22、8 65 97 76 13 27 49)树形选择排序,76,27,27,例:对(68,15,45,52,07,53,14)树形选择排序,叶子数n的完全二叉树深度为 log2n 1 第一次n1次比较,以后每次最多log2n 次,总时间不超过(n1)+n log2n =(nlog2n) 稳定,增加n1个单元保存结果,共2n1个单元 排序结果另外存储 与+的比较实际多余,一、定义,10.4.3 堆排序 Heap Sort,巧妙的树形选择排序,不需专门设立树。 将R1到Rn看成完全二叉树的顺序存储结构,利用双亲和孩子间的内在关系来选择关键字最小(或最大)的记录。,1)堆是一棵完全二叉树,任一结点关键字

23、小于等于(或大于等于)其孩子结点的关键字。 2)n个关键字序列K1,K2,Kn称为堆,当且仅当该序列满足: KiK2i且KiK2i+1 (1in/2) 或者 KiK2i且KiK2i+1 (1in/2),小根堆 大根堆,小根堆,大根堆,不是堆,不是堆,堆中任一棵子树也是堆,为保证时间性能,就要利用已有结果,每次输出堆顶后,剩下元素不是完全重建,应该在原堆上通过某些调整得到; 为保证空间性能,输出的堆顶应利用原有空间,可将它与无序区最后记录交换位置。排序过程中有序区在原记录区的尾部逐步形成并向前扩大,和直接选择排序相反。,二、堆排序基本思想,利用小(大)根堆选取当前无序区关键字最小(大)的记录来实

24、现排序。首先,将初始无序区调整为一个大根堆,输出关键字最大的堆顶记录后,将剩下的n1个记录再重建为堆,于是便得到次大值。如此反复,直到全部元素输出完。,两个问题: (1)最初如何由一个无序序列建成一个堆? (2)在输出堆顶元素后,如何调整剩余元素成为一个新的堆?,1、初始堆的建立,把完全二叉树中以每一结点为根的子树都调整为堆。,只有一个结点的树是堆,在完全二叉树中,所有序号in/2的结点都是叶子,以这些结点为根的子树均已是堆。,依次将以序号为n/2,n/21,1的结点作为根的子树都调整为堆。,按该次序调整各结点时,其左、右子树均已是堆(不妨将空树亦看作是堆)。,已知结点Ri的左、右子树是堆,如

25、何将以Ri为根的完全二叉树调整为堆?,解决这一问题可采用“筛选法”。,筛选法:,Ri左、右子树是堆,其根为各自子树中关键字最大者, 将Ri和其左、右孩子中关键字最大者放到Ri的位置。 若Ri是三者中的最大,则无需调整,以其为根的子树已是堆; 否则,将Ri和具有最大关键字的左孩子R2i或右孩子R2i+1进行交换。 交换后以R2i和R2i+1为根的子树可能不再是堆,但其左、右子树仍然是堆,于是重复上述过程,将子树调整为堆,如此逐层递推下去,最多可能一直调整到树叶。 这一过程就像过筛子一样,把较小的关键字筛下去,而将最大关键字一层层地选择上来。,大根堆,例,筛选法(大根堆)示例。,例,对(1,2,9

26、,11,4,6,8,10,16,05)建初始堆(大根)。 n=10,故从第10/2 5个结点开始进行调整,2、调整和重建,将堆顶元素与堆最后的元素互换; 将其余的元素筛选成堆;,交换,筛选,交换,筛选,交换,筛选,交换,筛选,交换,筛选,交换,筛选,交换,筛选,交换,筛选,交换,void HeapSort(list R,int n) /对R1到Rn进行堆排序int i;for(i=n/2;i=1;i) Sift(R,i,n); /建初始堆for(i=n;i=2;i) /进行n1趟堆排序R0=R1;R1=Ri;Ri=R0;/堆顶和当前堆底交换,R0作辅助量Sift(R,1,i1); /R1到Ri

27、1重建成新堆 ,三、算法实现,void Sift(list R,int p,int q) /筛选,范围RpRq,非递归int i,j;R0=Rp; /R0辅助量,保存原根结点i=p; /i指向待调整点j=2*i; /j指向Ri的左孩子while(jRj.key) break; /根孩子,已堆,调整结束Ri=Rj; /将Rj换到双亲位置上i=j; /修改当前被调整结点j=2*i; /j指向Ri的左孩子Ri=R0; /原根结点放入正确位置 ,void Sift2(list R,int p,int q) /筛选,范围RpRq,递归int i,j;if(p=q) return; /只有一个元素或无元素

28、i=p; /i指向待调整点j=2*i; /j指向Ri的左孩子if(jRj.key) return;/待调点已最大,不调R0=Rj;Rj=Ri;Ri=R0;/交换Rj和Ri,R0作辅助Sift2(R,j,q); /递归 ,建堆 n/2 筛选,重建n1次筛选,每次筛选双亲和孩子比较和移动,不超过深度,时间复杂度(n/2 n1)O(log2n) =O(nlog2n)。 辅助空间为1(供交换用),空间复杂度为O(1)。 不稳定,如(2,1,2),四、效率分析,一、 二路归并排序基本思想,初始排序表看成n个长度为1的有序子表,两两归并,得到 n/2 个有序的子表(当n为奇数时,归并后仍有一个长度为1的子

29、表);再把这些有序子表两两归并,如此反复,直到最后得到一个长度为n的有序表为止。,10.5 归并排序 (Merging Sort),利用“归并”技术来进行排序,所谓归并是指将若干个已排序的子表合并成一个有序表。,例,(49,38,65,97,76,13,49)二路归并排序。,void Merge(list R,list R1,int low,int mid,int high) /合并RlowRmid、Rmid+1Rhigh,结果在R1中int i,j,k;i=low;j=mid+1;k=low; while(i=mid /复制右子表剩余 ,1、两子表合并,二、算法实现,void MergePa

30、ss(list R,list R1,int n,int len) /对R做一趟归并,结果在R1中int i,j;i=1; /i指向第一对子表的起始点while(i+2*len1=n) /归并长度为len的两个子表Merge(R,R1,i,i+len1,i+2*len1);i=i+2*len; /i指向下一对子表起始点if(i+len1n) /剩两子表,一个长度小于lenMerge(R,R1,i,i+len1,n); else /子表个数为奇数,剩一段for(j=i;j=n;j+)/将最后一个子表复制到R1中R1j=Rj; ,2、一趟归并 设子表长度len,对子表个数奇数、最后子表长度小于len

31、两种情况特殊处理。,void MergeSort(list R,list R1,int n) /对R二路归并排序,结果在R中(非递归)int len;len=1;while(lenn) MergePass(R,R1,n,len);len=len*2;/一趟归并,结果在R1中MergePass(R1,R,n,len);len=len*2;/再次归并,结果在R中 ,3、归并排序 若干次调用“一趟归并”,每趟子表长度扩大一倍。第一趟子表长度为1,当子表长度n时结束。,三效率分析,子表长度不断加倍,1n,归并趟数为log2n;每趟归并比较次数移动次数,后者为O(n);总时间复杂度O(nlog2n)。

32、辅助空间为数组R1,空间复杂度O(n) 键值相同记录顺序复制,不改变相对位置,故是稳定的。 可在链表上实现,10.6 基数排序,利用关键字结构,通过“分配”和“收集”实现排序 无需比较关键字。 可分为箱排序和基数排序两类。,箱排序、桶排序 Bin Sort、Bucket Sort,设置若干箱子,扫描待排记录R1、R2、Rn,把关键字等于k的记录全都装入到第k个箱子(分配),然后,按序号依次将各非空的箱子首尾连接起来(收集)。,例,扑克牌按面值A2JQK排序(不分花色),设置13个“箱子”,依次将每张牌按面值放入相应的箱子里,然后依次将箱子首尾相接,就得到按面值递增序排列的一副牌。,箱子个数m取

33、决于关键字的取值范围。 分配时间(n),收集时间(m+n)(若用链表,则(m)),所以箱排序时间(m+n)。 若关键字的取值范围很大,如m=(n2),则效率很低。,基数排序 (Radix Sort),多关键字排序:低位优先,高位优先 每趟箱子共用,每趟排序前清空箱子(除第一趟外) 箱子的数据按队列存放 箱子内数据个数可变,适合链表实现链式基数排序,将关键字看成多个分量组成,从低到高依次对关键字的各分量进行箱排序,每趟所需箱子数就是基数。,时间:链表初始化O(n),清箱O(r),收集O(r),分箱O(n),一趟总O(n+r),d趟总O(d(n+r)O(n)。 空间:结点指针O(n),箱子头尾指针

34、O(r),总O(n+r) 稳定:分配和收集不改变相同键值的相对位置。,例 对( 91 46 85 15 92 35 31 22)基数排序,0,1,2,3,4,5,6,7,8,9,91,46,85,15,92,35,31,22,收集: 91 31 92 22 85 15 35 46,0,1,2,3,4,5,6,7,8,9,91,31,92,22,85,15,35,46,收集: 15 22 31 35 46 85 91 92,分配(按个位),分配(按十位),10.7 内排序的比较和选择,简单排序(直接插入、直接选择、冒泡排序等)每次只对相邻元素比较,前进步伐慢,时间耗费大,为(n2),但一些特殊情况却可取得很好效果;效率高的算法每次比较产生的作用不仅仅局限于被比较的两个元素,而是多个甚至一半左右,但它们对数据量小的情况并不一定合适。,综合考虑下列因素: (1)待排序的记录数目。 (2)记录本身信息量的大小。 (3)关键字的结构及其分布情况。 (4)对排序稳定性的要求。 (5)语言工具的条件。 (6)算法本身的难易程度。 (7)辅助空间的大小等。,

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

当前位置:首页 > 企业管理 > 管理学资料

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


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

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

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