260 likes | 533 Views
归并排序. 基本原理,通过对两个有序结点序列的合并来实现排序。 所谓归并是指将若干个已排好序的部分合并成一个有序的部分。. 两路归并的基本思想. 设有两个有序表 A 和 B ,对象个数分别为 a l 和 b l ,变量 i 和 j 分别是两表的当前指针。设表 C 是归并后的新有序表,变量 k 是它的当前指针。 i 和 j 对 A 和 B 遍历时,依次将关键字小的对象放到 C 中,当 A 或 B 遍历结束时,将另一个表的剩余部分照抄到新表中。. 两路归并的示例. 25 57 48 37 12 92 86. 25 57 37 48 12 92 86.
E N D
归并排序 • 基本原理,通过对两个有序结点序列的合并来实现排序。 • 所谓归并是指将若干个已排好序的部分合并成一个有序的部分。
两路归并的基本思想 设有两个有序表A和B,对象个数分别为al和bl,变量i和j分别是两表的当前指针。设表C是归并后的新有序表,变量k是它的当前指针。i和j对A和B遍历时,依次将关键字小的对象放到C中,当A或B遍历结束时,将另一个表的剩余部分照抄到新表中。
两路归并的示例 255748 37129286 25 5737 4812 9286 25 37 48 5712 86 92 12 25 37 48 57 86 92
归并算法 Merge(rectypr R[],rectype R1[],int low,int mid,int high) { int i,j,k; i=low; j=mid+1; k=low; while ((i<=mid)&&(j<=high)) if (R[i].key<=R[j].key) R1[k++]=R[i++]; else R1[k++]=R[j++]; while (j<=mid) R1[k++]=R[i++]; while (j<=high) R1[k++]=R[j++]; }
归并排序就是利用上述归并操作实现排序的。其基本思想是:归并排序就是利用上述归并操作实现排序的。其基本思想是: 将待排序列R[0]到R[n-1]看成n个长度为1的有序子序列,把这些子序列两两归并,便得到high(n/2)个有序的子序列。然后再把这high(n/2)个有序的子序列两两归并,如此反复,直到最后得到一个长度为n的有序序列。上述每次的归并操作,都是将两个子序列归并为一个子序列,这就是“二路归并”,类似地还可以有“三路归并”或“多路归并”。
归并过程示例 (25) (57) (48) (37) (12) (92) (86) (25 57) (37 48) (12 92) (86) (25 37 48 57) (12 86 92) (12 25 37 48 57 86 92)
一趟归并算法 Mergepass(rectype R[],rectype R1[],int length) { int i,j; i=0; while (i+2*length-1<n) { MERGE(R,R1,i,i+length-1,i+2*length-1); i=i+2*length; } if (i+length-1<n-1) MERGE(R,R1,i,i+length-1,n-1); else for (j=i;j<n;j++) R1[j]=R[j]; }
归并排序算法 Mergesort(rectype R[]) { int length=1; while (length<n) { Mergepass(R,R1,length); length=2*length; Mergepass(R1,R,length); length=2*length; } }
算法复杂性分析 归并排序在第i 趟归并后,有序子文件长度为2i,因此,因此,对于具有n个记录的序列来说,必须做high(log2n)趟归并,每趟归并所花的时间为O(n)。所以,二路归并排序算法的时间复杂度为O(nlog2n),辅助数组所需的空间为O(n)。 归并排序是稳定的排序方法。
基数排序 • 基本原理,采用“分配”和“收集”的办法,用对多关键字进行排序的思想实现对单关键字进行排序的方法。 • 下面先介绍多关键字排序
多关键字排序方法示例 • 如对扑克牌的排序 • 每张扑克牌有两个“关键字”:花色和面值它们之间有次序的优先。 • 对以上排序,可以先对花色排序,或先对面值排序。
多关键字有序的概念 • 考虑对象序列{V0,V1,..., Vn-1},每个对象Vi含d个关键字(Ki1,Ki2,..., Kid)。若对序列中的任意两个对象Vi和Vj都有 (Ki1,Ki2,..., Kid) < (Kj1,Kj2,..., Kjd) • 则称序列对关键字(Ki1,Ki2,..., Kid)有序,且K1称为最高位关键字,Kd称为最低位关键字。
多关键字排序 • 原理:根据组成关键字的各位的值进行排序。 实现基数排序的两种方法: 1 最高位优先(MSD)排序:从关键字的高位到低位 2 最低位优先(LSD)排序:从关键字的低位到高位 • MSD方法通常是一个递归的过程。
多关键字排序(续) • LSD和MSD方法也可应用于对一个关键字进行的排序。此时可将单关键字Ki看成是一个子关键字组: (Ki1,Ki2,..., Kid) • 如对关键字取值范围为0到999的一组对象,可看成是(K1,K2,K3)的组合。 • MSD方法按K1,K2,K3的顺序对所有对象排序;LSD方法按K3 ,K2 , K1的顺序对所有对象排序。
链式的基数排序 • 基数排序是一种典型的LSD排序方法,它利用“分配”和“收集”两种运算对单关键字进行排序。 • 此时可将单关键字K看成是一个子关键字组: (Ki1,Ki2,..., Kid) • 排序过程:设关键字共有d位,让j= d, d-1,...,1, 依次执行d次“分配”与“收集”。
179 208 306 93 859 984 55 9 271 33 B[0].f B[1].f B[2].f B[3].f B[4].f B[5].f B[6].f B[7].f B[8].f B[9].f 271 93 984 55 306 208 179 859 33 9 B[0].e B[1].e B[2].e B[3].e B[4].e B[5].e B[6].e B[7].e B[8].e B[9].e
271 93 33 984 55 306 208 179 859 9 B[0].f B[1].f B[2].f B[3].f B[4].f B[5].f B[6].f B[7].f B[8].f B[9].f 306 33 55 271 984 93 208 859 179 9 B[0].e B[1].e B[2].e B[3].e B[4].e B[5].e B[6].e B[7].e B[8].e B[9].e
306 208 9 33 55 859 271 179 984 93 B[0].f B[1].f B[2].f B[3].f B[4].f B[5].f B[6].f B[7].f B[8].f B[9].f 9 179 208 306 859 984 33 271 55 93 B[0].e B[1].e B[2].e B[3].e B[4].e B[5].e B[6].e B[7].e B[8].e B[9].e 9 33 55 93 179 208 271 306 859 984
分配排序算法 typedef struct { int key[d]; int next; datatype other; } rectype; rectype R[n]; typedef struct { int f,e; } queue; queue B[m];
for (j=d-1;j>=0;j--) { for (i=0;i<m;i++) { B[i].f=-1; B[i].e=-1; } while (p!=-1) { k=R[p].key[j]; if (B[k].f==-1) B[k].f=p; else R[B[k].e].next=p; B[k].e=p; p=R[p].next; } i=0; while (B[i].f==-1) i++; t=B[i].e; p=B[i].f; while (i<m-1) { i++; if (B[i].f!=-1) {R[t].next=B[i].f; t=B[i].e;} } R[t].next=-1; } return p; } int RADIXSORT (rectype R[]) { int i,j,k,t,p; for (i=0;i<n-1;i++) R[i].next=i+1; R[n-1].next=-1; p=0;
内部排序方法的比较和选择 • 选取排序方法时需要考虑的因素有: • 待排序的记录数目 • 记录本身信息量的大小 • 关键字的结构及其分布情况 • 对排序稳定性的要求 • 语言工具的条件、辅助空间的大小
外部排序简介 如果待排序的记录数很大,无法将所有记录都调入内存,只能将它们存放在外存上,我们称这时的排序为外部排序。 外部排序的实现,主要是依靠数据的内外存交换和“内部归并”。