收藏 分享(赏)

数据结构(第十章 排序).ppt

上传人:精品资料 文档编号:9437764 上传时间:2019-08-07 格式:PPT 页数:107 大小:3.20MB
下载 相关 举报
数据结构(第十章 排序).ppt_第1页
第1页 / 共107页
数据结构(第十章 排序).ppt_第2页
第2页 / 共107页
数据结构(第十章 排序).ppt_第3页
第3页 / 共107页
数据结构(第十章 排序).ppt_第4页
第4页 / 共107页
数据结构(第十章 排序).ppt_第5页
第5页 / 共107页
点击查看更多>>
资源描述

1、数 据 结 构,第 10 章 排序,概述,10.1 概述10.2 插入排序10.3 快速排序10.4 选择排序10.5 归并排序10.6 基数排序10.7 各种内部排序方法的比较,10.1 概述,一、什么是排序?,排序是计算机内经常进行的一种操作,其目的是将一组无序的记录序列调整为“有序”的记录序列。,例如:将下列关键字序列,52, 49, 80, 36, 14, 58, 61, 23, 97, 75,调整为,14, 23, 36, 49, 52, 58, 61 ,75, 80, 97,一般情况下, 假设含n个记录的序列为 R1, R2, , Rn 其相应的关键字序列为 K1, K2, ,Kn

2、 ,10.1 概述,这些关键字相互之间可以进行比较,即在它们之间存在着这样一个关系:Kp1Kp2Kpn,按此固有关系将上式记录序列重新排列为 Rp1, Rp2, ,Rpn 的操作称作排序。,数据表(data list): 它是待排序数据对象的有限集合。,10.1 概述,主关键字(key):是数据元素中的某个数据项。如果某个数据 项可以唯一地确定一个数据元素,就将其称为主关键字; 否则,称为次关键字。,学号 姓名 专业 年龄 01 王洪 计算机 17 06 余斌 计算机 19 07 巩力 计算机 17 02 孙文 计算机 18 04 李辉 计算机 20 03 谢军 计算机 18 05 沈祥福 计

3、算机 25 08 王辉 计算机 18,10.1 概述,排序方法的稳定性: 如果在对象序列中有两 个对象ri和rj, 它们的排序码 ki = kj , 在排序之前, 对象ri排在rj前面。如果在排序之后, 对象ri仍在对象rj的前面, 则称这个排序方法是稳定的, 否则称这个排序方法是不稳定的。内排序与外排序: 内排序是指在排序期间数据对象全部存放在内存的排序;外排序是指在排序期间全部对象个数太多,不能同时存放在内存,必须根据排序过程的要求,不断在内、外存之间移动的排序。,10.1 概述,内部排序的方法,内部排序的过程是一个逐步扩大记录的有序序列长度的过程。,经过一趟排序,有序序列区,无 序 序

4、列 区,有序序列区,无 序 序 列 区,排序的时间开销:排序的时间开销是衡量算法好坏的最重要的标志。排序的时间开销可用算法执行中的数据比较次数与数据移动次数来衡量。,10.1 概述,内排序分类,依不同原则插入排序、交换排序、选择排序、归并排序、和基数排序等。依所须工作量简单排序-时间复杂度o(n2)先进排序方法-时间复杂度o(n logn)基数排序-时间复杂度o(d*n),10.2 插入排序,有序序列R1i-1,Ri,无序序列 Rin,有序序列R1i,无序序列 Ri+1n,基本思想: 每步将一个待排序的对象, 按其排序码大小, 插入到前面已经排好序的一组对象的适当位置上, 直到对象全部插入为止

5、。,10.2 插入排序,实现“一趟插入排序”可分三步进行:,3将Ri 插入(复制)到Rj+1的位置上。,2将Rj+1i-1中的所有记录均后移一个位置;,1在R1i-1中查找Ri的插入位置;R1j.key Ri.key Rj+1i-1.key,10.2 插入排序,直接插入排序(基于顺序查找),表插入排序(基于链表存储),不同的具体实现方法导致不同的算法描述,折半插入排序(基于折半查找),希尔排序(基于逐趟缩小增量),10.2 插入排序,直接插入排序,基本思想: 当插入第i (i 1) 个对象时, 前面的V0, V1, , Vi-1已经排好序。这时, 用Vi的排序码与Vi-1, Vi-2, 的排序

6、码顺序进行比较, 找到插入位置即将Vi插入, 原来位置上的对象向后顺移。,10.2 插入排序,直接插入排序,从Ri-1起向前进行顺序查找,监视哨设置在R0;,R0 = Ri; / 设置“哨兵”,循环结束表明Ri的插入位置为 j +1,R0,Ri,for (j=i-1; R0.keyRj.key; -j); / 从后往前找,插入位置,对于在查找过程中找到的那些关键字不小于Ri.key的记录,并在查找的同时实现记录向后移动;,for (j=i-1; R0.keyRj.key; -j) Rj+1 = Rj,R0,Ri,上述循环结束后可以直接进行“插入”,插入位置,10.2 插入排序,直接插入排序,1

7、0.2 插入排序,直接插入排序,令 i = 2,3,, n, (i=1时元素自身有序)实现整个序列的排序。,for ( i=2; i=n; +i )if (Ri.keyRi-1.key) 在 R1i-1中查找Ri的插入位置;插入Ri ;,10.2 插入排序,直接插入排序,void InsertionSort ( SqList / 插入到正确位置 / InsertSort,10.2 插入排序,直接插入排序,算法分析,设待排序对象个数为 n, 则该算法的主程序执行n-1趟。排序码比较次数和对象移动次数与对象排序码的初始排列有关。最好情况下, 排序前对象已按排序码从小到大有序, 每趟只需与前面有序对

8、象序列的最后一个对象比较1次, 移动0次对象, 总的排序码比较次数为 n-1。,10.2 插入排序,直接插入排序,最坏情况下, 第 i 趟时第 i 个对象必须与前面 i 个对象都做排 序码比较, 并且每做1次比较就要做1次数据移动。则总排序 码比较次数KCN和对象移动次数RMN分别为在平均情况下的排序码比较次数和对象动次数约为 n2/4。因此,直接插入排序的时间复杂度为 o(n2)。 直接插入排序是一种稳定的排序方法。,10.2 插入排序,折半插入排序,基本思想: 因为 R1i-1 是一个按关键字有序的有序序列,则可以利用折半查找实现“在R1i-1中查找Ri的插入位置”,如此实现的插入排序为折

9、半插入排序。,10.2 插入排序,折半插入排序,void BiInsertionSort ( SqList &L ) / BInsertSort,在 L.r1i-1中折半查找插入位置;(见下页),for ( i=2; i=L.length; +i ) / for,L.r0 = L.ri; / 将 L.ri 暂存到 L.r0,for ( j=i-1; j=high+1; -j )L.rj+1 = L.rj; / 记录后移,L.rhigh+1 = L.r0; / 插入,10.2 插入排序,折半插入排序,low = 1; high = i-1; while (low=high) ,m = (low+

10、high)/2; / 折半,if (L.r0.key L.rm.key)high = m-1; / 插入点在低半区 else low = m+1; / 插入点在高半区,(接上页)在 L.r1i-1中折半查找插入位置;,10.2 插入排序,折半插入排序,i,low,high,m,m,low,low,m,high,i,low,high,m,high,m,high,m,low,例如:,再如:,插入 位置,插入 位置,10.2 插入排序,折半插入排序,折半搜索比顺序搜索查找快, 所以折半插入排序就平均性能来说比直接插入排序要快。 它所需的排序码比较次数与待排序对象序列的初始排列无关, 仅依赖于对象个数

11、。在插入第 i 个对象时, 需要经过 log2i +1 次排序码比较, 才能确定它应插入的位置。因此, 将 n 个对象(为推导方便, 设为 n=2k )用折半插入排序所进行的排序码比较次数为:,算法分析,10.2 插入排序,折半插入排序,当 n 较大时, 总排序码比较次数比直接插入排序的最坏情况要好得多, 但比其最好情况要差。在对象的初始排列已经按排序码排好序或接近有序时, 直接插入排序比折半插入排序执行的排序码比较次数要少。折半插入排序的对象移动次数与直接插入排序相同, 依赖于对象的初始排列。折半插入排序是一个稳定的排序方法。折半插入排序的时间复杂度为o(n2)。,10.2 插入排序,表插入

12、排序,为了减少在排序过程中进行的“移动”记录的操作,必须改变排序过程中采用的存储结构。利用静态链表进行排序,并在排序完成之后,一次性地调整各个记录相互之间的位置,即将每个记录都调整到它们所应该在的位置上。,10.2 插入排序,表插入排序,1,例:关键字序列 T=(21,25,49,25*,16,08),请写出表插入排序的具体实现过程。,解:假设该序列(结构类型)已存入一维数组V7中,将V0作为表头结点。则算法执行过程为:,指向第1个元素,指向头结点,初态 i=1,i=2,i=3,i=4,i=5,i=6,0,3,4,5,6,5,0,3,1,0,2,*表示后一个25,10.2 插入排序,表插入排序

13、,算法中使用了三个指针: 其中:p指示第i个记录的当前位置;i指示第i个记录应在的位置;q指示第i+1个记录的当前位置,如何在排序之后调整记录序列?,void Arrange ( Elem SL , int n ) p = SL0.next; / p指示第一个记录的当前位置for ( i=1; in; +i ) while (pi) p = SLp.next;q = SLp.next; / q指示尚未调整的表尾if ( p!= i ) SLpSLi; / 交换记录,使第i个记录到位SLi.next = p; / 指向被移走的记录, /ifp = q; / p指示尚未调整的表尾,准备找第i+1个

14、记录/for / Arrange,10.2 插入排序,表插入排序,10.2 插入排序,希尔排序,基本思想:设待排序对象序列有 n 个对象, 首先取一个整数 gap n 作为间隔, 将全部对象分为 gap 个子序列, 所有距离为 gap 的对象放在同一个子序列中, 在每一个子序列中分别施行直接插入排序。然后缩小间隔 gap, 例如取 gap = gap/2,重复上述的子序列划分和排序工作。直到最后取 gap = 1, 将所有对象放在同一个序列中排序为止。,10.2 插入排序,希尔排序,i = 3,Gap = 3,0 1 2 3 4 5,i = 2,Gap = 2,21,08,25,49,25*,

15、16,i = 1,Gap = 1,希尔排序过程,21,25*25,1649,08,21,08,2516,25*,49,10.2 插入排序,希尔排序,void ShellInsert ( SqList / 插入 / if / ShellInsert,10.2 插入排序,希尔排序,void ShellSort (SqList /一趟增量为dltak的插入排序 / ShellSort,10.2 插入排序,希尔排序,开始时 gap 的值较大, 子序列中的对象较少, 排序速度较快; 随着排序进展, gap 值逐渐变小, 子序列中对象个数逐渐变多, 由于前面大多数对象已基本有序, 所以排序速度仍然很快。

16、Gap的取法有多种。 shell 提出取 gap = n/2,gap = gap/2,直到gap = 1。 对特定的待排序对象序列,可以准确地估算排序码的比较次数和对象移动次数。 希尔排序所需的比较次数和移动次数约为n 1.3当n趋于无穷时可减少到n(log2 n)2,算法分析,10.3 快速排序,基本思想是两两比较待排序对象的排序码,如发生逆序(即排列顺序与排序后的次序正好相反),则交换之,直到所有对象都排好序为止。,10.3 快速排序,起泡排序,基本方法设待排序对象序列中的对象个数为n。一般地,第i趟起泡排序从1到n-i+1依次比较相邻两个记录地关键字,如果发生逆序,则交换之,其结果是这n

17、-i+1个记录中,关键字最大的记录被交换到第n-i+1的位置上,最多作n-1趟。,10.3 快速排序,起泡排序,假设在排序过程中,记录序列R1n的状态为:,第 i 趟起泡排序,无序序列R1n-i+1,有序序列 Rn-i+2n,n-i+1,无序序列R1n-i,有序序列 Rn-i+1n,比较相邻记录,将关键字最大的记录交换到 n-i+1 的位置上,10.3 快速排序,起泡排序,21,08,25,49,25,16,21,49,25,25,16,08,21,49,25,25,16,08,初 始 关 键 字,第 一 趟 排 序,第 四 趟 排 序,第 二 趟 排 序,第 三 趟 排 序,21,49,25

18、,25,16,08,第 五 趟 排 序,起泡排序的过程,10.3 快速排序,起泡排序,起泡排序的算法typedef int SortData; void BubbleSort ( SortData V , int n ) int i = 1; int exchange = 1;while ( i = i; j- )if ( Vj-1 Vj ) /逆序 Swap ( Vj-1, Vj ); /交换exchange = 1; /标志置为1,有交换 i+; ,10.3 快速排序,起泡排序,时间分析,第i趟对待排序对象序列Vi-1,Vi,Vn-1进行排序, 结果将该序列中排序码最小的对象交换到序列的第

19、一个位置(i-1), 其它对象也都向排序的最终位置移动。最多做n-1趟起泡就能把所有对象排好序。在对象的初始排列已经按排序码从小到大排好序时,此算法只执行一趟起泡,做n-1次排序码比较,不移动对象。这是最好的情形。,最坏的情形是算法执行n-1趟起泡,第i趟 (1 i n) 做 n- i 次排序码比较, 执行 n-i 次对象交换。这样在最坏情形下总的排序码比较次数KCN和对象移动次数RMN为:,起泡排序是一个稳定的排序方法。,10.3 快速排序,起泡排序,10.3 快速排序,一趟快速排序,目标:找一个记录,以它的关键字作为“枢轴”,凡其关键字小于枢轴的记录均移动至该记录之前,反之,凡关键字大于枢

20、轴的记录均移动至该记录之后。,致使一趟排序之后,记录的无序序列Rst将分割成两部分:Rsi-1和Ri+1t, 且 Rj.key Ri.key Rj.key(sji-1) 枢轴 (i+1jt),10.3 快速排序,一趟快速排序,设 Rs=52 为枢轴暂存在R0的位置上,将 Rhigh.key 和 枢轴的关键字进行比较,要求Rhigh.key 枢轴的关键字,将 Rlow.key 和 枢轴的关键字进行比较,要求Rlow.key 枢轴的关键字,23,80,14,52,例如,R0,52,10.3 快速排序,一趟快速排序,可见,经过“一次划分” ,将关键字序列52, 49, 80, 36, 14, 58,

21、 61, 97, 23, 75 调整为: 23, 49, 14, 36, (52) 58, 61, 97, 80, 75,在调整过程中,设立了两个指针: low 和high,它们的初值分别为: s 和 t,之后逐渐减小 high,增加 low,并保证 Rhigh.key52,和 Rlow.key52,否则进行记录的“交换”。,10.3 快速排序,一趟快速排序,int Partition (RedType R, int low, int high) / Partition,R0 = Rlow; pivotkey = Rlow.key; / 枢轴,while (lowhigh) ,while(lo

22、w=pivotkey)- high; / 从右向左搜索,Rlow = Rhigh;,while (lowhigh / 从左向右搜索,Rhigh = Rlow;,Rlow = R0; return low;,10.3 快速排序,快速排序,首先对无序的记录序列进行“一次划分”,之后分别对分割所得两个子序列“递归”进行快速排序。,无 序 的 记 录 序 列,无序记录子序列(1),无序子序列(2),枢轴,一次划分,分别进行快速排序,10.3 快速排序,快速排序,void QSort (RedType & R, int s, int t ) / 对记录序列Rst进行快速排序if (lowhigh) /

23、长度大于1 / QSort,pivotloc = Partition(R, s, t);/ 对 Rst 进行一次划分,QSort(R, s, pivotloc-1);/ 对低子序列递归排序,pivotloc是枢轴位置,QSort(R, pivotloc+1, t); / 对高子序列递归排序,10.3 快速排序,快速排序,void QuickSort( SqList / QuickSort,第一次调用函数 Qsort 时,待排序记录序列的上、下界分别为 1 和 L.length。,10.3 快速排序,快速排序,快速排序的过程,21,08,25,49,25*,16,初始关键字,08,25,49,2

24、5*,16,21,08,25,49,25*,16,08,25,49,25*,16,08,25,49,25*,16,08,25,49,25*,16,21,pivotkey,一次交换,二次交换,三次交换,四次交换,完成一趟排序,i,j,i,j,j,i,10.3 快速排序,快速排序,08,25,49,25*,16,21,完成一趟排序,分别进行快速排序,08,25,49,25*,16,21,有序序列,08,25,49,25*,16,21,10.3 快速排序,快速排序,算法quicksort是一个递归的算法, 其递归树如图所示。算法partition利用序列第一个对象作为基准,将整个序列划分为左右两个子

25、序列。算法中执行了一个循环, 只要是排序码小于基准对象排序码的对象都移到序列左侧, 最后基准对象安放到位, 函数返回其位置。,10.3 快速排序,快速排序,算法分析,快速排序的趟数取决于递归树的高度。如果每次划分对一个对象定位后, 该对象的左侧子序列与右侧子序列的长度相同, 则下 一步将是对两个长度减半的子序列进行排序, 这是最理想的情况。在 n个元素的序列中, 对一个对象定位所需时间为 O(n)。若设 t (n) 是对 n 个元素的序列进行排序所需的时间, 而且每次对一个对象正确定位后, 正好把序列划分为长度相等的两个子序列, 此时, 总的计算时间为O(n log2n ),可以证明, 函数q

26、uicksort的平均计算时间也是O(nlog2n)。实验结果表明: 就平均计算时间而言, 快速排序是所有内排序方法中最好的一个。快速排序是递归的,需要有一个栈存放每层递归调用时的指针和参数。快速排序是一种不稳定的排序方法。,10.3 快速排序,快速排序,10.4 选择排序,基本思想 每一趟 (例如第 i 趟, i = 1,2, , n-2) 在后面 n-i +1个待排序记录中选出排序码最小的记录, 作为有序序列中的第 i 个记录。待到第n-1 趟作完, 待排序记录只剩下1个,就不用再选了。,10.4 选择排序,直接选择排序是一种简单的排序方法, 它的基本步骤是: 在一组对象 ViVn 中选择

27、具有最小排序码的对象; 若它不是这组对象中的第一个对象, 则将它与这组对象中的第一个对象对调; 在这组对象中剔除这个具有最小排序码的对象。在剩下的对象Vi+1Vn中重复执行第、步, 直到剩余对象只有一个为止。,直接选择排序,10.4 选择排序,直接选择排序,假设排序过程中,待排记录序列的状态为:,有序序列R1i-1,无序序列 Rin,第 i 趟 简单选择排序,从中选出 关键字最小的记录,有序序列R1i,无序序列 Ri+1n,10.4 选择排序,直接选择排序,直接选择排序的过程,10.4 选择排序,直接选择排序,最小者 25* 无交换,10.4 选择排序,直接选择排序,简单选择排序的算法描述如下

28、:,void SelectSort (Elem R, int n ) / 对记录序列R1n作简单选择排序。for (i=1; in; +i) / 选择第 i 小的记录,并交换到位 / SelectSort,j = SelectMinKey(R, i); / 在 Rin 中选择关键字最小的记录,if (i!=j) RiRj;/ 与第 i 个记录交换,10.4 选择排序,直接选择排序,直接选择排序的排序码比较次数 KCN 与对象的初始排列无关。设整个待排序对象序列有 n 个对象, 则第 i 趟选择具有最小排序码对象所需的比较次数总是 n-i-1 次。总的排序码比较次数为,对象的移动次数与对象序列的

29、初始排列有关。当这组对象的初始状态是按其排序码从小到大有序的时候, 对象的移动次数RMN = 0,达到最少。 最坏情况是每一趟都要进行交换,总的对象移动次数为 RMN = 3(n-1)。 直接选择排序是一种不稳定的排序方法。,10.4 选择排序,堆排序,堆 ( Heap )设有一个关键字集合,按完全二叉树的顺序存储方式存放在一个一维数组中。对它们从根开始,自顶向下,同一层自左向右从 0开始连续编号。若满足Ki K2i+1 & Ki K2i+2 或 Ki K2i+1 & Ki K2i+2, 则称该关键字集合构成一个堆。前者成为小顶堆,后者称为大顶堆。,10.4 选择排序,堆排序,10.4 选择排

30、序,堆排序,利用堆及其运算, 可以很容易地实现选择排序的思路。堆排序分为两个步骤根据初始输入数据,利用堆的调整算法 形成初始堆;通过一系列的对象交换和重新调整堆进行排序。,10.4 选择排序,堆排序,初始大顶堆的建立过程,3,初始排序码集合,i = 2 时的局部调整,21,25,25*,49,16,08,0,1,2,3,4,5,i,49,25,25*,16,21,08,0,2,5,4,3,1,10.4 选择排序,堆排序,10.4 选择排序,堆排序,基于初始堆(大顶堆)进行堆排序,最大堆堆顶V0具有最大的排序码, 将V0与 Vn-1对调, 把具有最大排序码的对象交换到最后, 再对前面的n-1个对

31、象, 使用堆的调整算法, 重新建立最大堆, 具有次最大排序码的对象又上浮到V0位置。再对调V0和Vn-2,调用堆的调整算法,对前n-2个对象重新调整,。如此反复执行,最后得到全部排序好的对象序列。这个算法即堆排序算法,,10.4 选择排序,堆排序,49 25 21 25* 16 08,08 25 21 25* 16 49,交换 0 号与 5 号对象, 5 号对象就位,初始最大堆,基于初始堆进行堆排序,10.4 选择排序,堆排序,08,16,49,08,25,49,25 25* 21 08 16 49,16 25* 21 08 25 49,交换 0 号与 4 号对象, 4 号对象就位,从 0 号

32、到 4 号 重新 调整为最大堆,10.4 选择排序,堆排序,25* 16 21 08 25 49,08 16 21 25* 25 49,交换 0 号与 3 号对象, 3 号对象就位,从 0 号到 3 号 重新 调整为最大堆,10.4 选择排序,堆排序,21 16 08 25* 25 49,08 16 21 25* 25 49,交换 0 号与 2 号对象, 2 号对象就位,从 0 号到 2 号 重新 调整为最大堆,10.4 选择排序,堆排序,16,08,25*,21,25,49,0,1,2,3,4,5,08,16,25*,25,21,49,0,2,5,4,3,1,16 08 21 25* 25

33、49,08 16 21 25* 25 49,交换 0 号与 1 号对象, 1 号对象就位,从 0 号到 1 号 重新 调整为最大堆,10.4 选择排序,堆排序,void HeapSort ( HeapType &H ) / 对顺序表 H 进行堆排序。 / HeapSort,for ( i=H.length/2; i0; -i )HeapAdjust ( H.r, i, H.length ); / 建大顶堆,for ( i=H.length; i1; -i ) H.r1H.ri; / 将堆顶记录和当前未经排序子序列/ H.r1i中最后一个记录相互交换HeapAdjust(H.r, 1, i-1)

34、; / 对 H.r1 进行筛选 ,堆排序的算法,10.4 选择排序,堆排序,void HeapAdjust (RcdType &R, int s, int m) / 已知 Rsm中记录的关键字除 Rs 之外均/ 满足堆的特征,本函数自上而下调整 Rs 的/ 关键字,使 Rsm 也成为一个大顶堆。 / HeapAdjust,rc = Rs; / 暂存 Rs,for ( j=2*s; j=m; j*=2 ) / j 初值指向左孩子自上而下的筛选过程; ,Rs = rc; / 将调整前的堆顶记录插入到 s 位置,10.4 选择排序,堆排序,if ( rc.key = Rj.key ) break;

35、/ 再作“根”和“子树根”之间的比较,/ 若“=”成立,则说明已找到 rc 的插/ 入位置 s ,不需要继续往下调整,Rs = Rj; s = j; / 否则记录上移,尚需继续往下调整,if ( jm / 左/右“子树根”之间先进行相互比较/ 令 j 指示关键字较大记录的位置,自上而下的筛选过程;,10.4 选择排序,堆排序,建堆是一个从下往上进行“筛选”的过程。,40,55,49,73,81,64,36,12,27,98,例如: 排序之前的关键字序列为,12,36,81,73,49,98,81,73,55,现在,左/右子树都已经调整为堆,最后只要调整根结点,使整个二叉树是个“堆”即可。,98

36、,49,40,64,36,12,27,10.4 选择排序,堆排序,堆排序的时间复杂度分析:,1. 对深度为 k 的堆,“筛选”所需进行的关键字比较的次数至多为2(k-1);,2. 对 n 个关键字,建成深度为 h (=log2n+1) 的堆,所需进行的关键字比较的次数至多 4n;,3. 调整“堆顶” n-1 次,总共进行的关键字比较的次数不超过2 (log2(n-1)+ log2(n-2)+ +log22) 2n(log2n),因此,堆排序的时间复杂度为O(nlogn),10.5 归并排序,归并排序的过程基于下列基本思想进行:将两个或两个以上的有序表合并成一个新的有序表。两路归并 (2-way

37、 merging)原始序列initList 中两个有序表 initListl initListm和initListm+1 initListn,它们可归并成一个有序表, 存于另一对象序列mergedList的 l n 中。,10.5 归并排序,2-路归并排序。即:将两个位置相邻的记录有序子序列,归并为一个记录的有序序列。,有 序 序 列 Rln,有序子序列 Rlm,有序子序列 Rm+1n,这个操作对顺序表而言,是轻而易举的。,10.5 归并排序,void Merge (RcdType SR, RcdType &TR, int i, int m, int n) / 将有序的记录序列 SRim 和

38、SRm+1n/ 归并为有序的记录序列 TRin / Merge,for (j=m+1, k=i; i=m , ,10.5 归并排序,if (i=m) TRkn = SRim;/ 将剩余的 SRim 复制到 TR,if (j=n) TRkn = SRjn;/ 将剩余的 SRjn 复制到 TR,10.5 归并排序,迭代的归并排序算法,迭代的归并排序算法就是利用两路归并过程进行排序的。其基本思想是: 假设初始对象序列有 n 个对象,首先把它看成是 n 个长度为 1 的有序子序列 (归并项),先做两两归并,得到 n / 2 个长度为 2 的归并项 (如果 n 为奇数,则最后一个有序子序列的长度为1);

39、再做两两归并,如此重复,最后得到一个长度为 n 的有序序列。,10.5 归并排序,迭代的归并排序算法,21,25,25*,25*,93,62,72,08,37,16,54,49,21,25,49,62,93,08,72,16,37,54,21,25,25*,49,08,62,72,93,16,37,54,08,08,21,16,25,21,25*,25,49,25*,62,37,72,49,93,54,16,37,54,62,72,93,len=1,len=2,len=4,len=8,len=16,10.5 归并排序,void Msort ( RcdType SR, RcdType else

40、/ Msort, ,10.5 归并排序,m = (s+t)/2;/ 将SRst平分为SRsm和SRm+1t,Msort (SR, TR2, s, m);/ 递归地将SRsm归并为有序的TR2sm Msort (SR, TR2, m+1, t);/递归地SRm+1t归并为有序的TR2m+1t,Merge (TR2, TR1, s, m, t);/ 将TR2sm和TR2m+1t归并到TR1st,10.5 归并排序,void MergeSort (SqList / MergeSort,容易看出,对 n 个记录进行归并排序的时间复杂度为(nlogn)。即:每一趟归并的时间复杂度为 O(n),总共需进行

41、 log2n 趟。,10.6 基数排序,基数排序是一种借助“多关键字排序”的思想来实现“单关键字排序”的内部排序算法。,多关键字的排序,链式基数排序,10.6 基数排序,多关键字的排序,n 个记录的序列 R1, R2, ,Rn 对关键字 (Ki0, Ki1,Kid-1) 有序是指:,其中: K0 被称为 “最主”位关键字,,Kd-1 被称为 “最次”位关键字。,对于序列中任意两个记录 Ri 和 Rj (1ijn) 都满足下列有序关系:(Ki0, Ki1, ,Kid-1) (Kj0, Kj1, ,Kjd-1),10.6 基数排序,多关键字的排序,实现多关键字排序通常有两种作法:,最低位优先LSD

42、法:,最高位优先MSD法:,先对K0进行排序,并按 K0 的不同值将记录序列分成若干子序列之后,分别对 K1 进行排序,., 依次类推,直至最后对最次位关键字排序完成为止。,先对 Kd-1 进行排序,然后对 Kd-2 进行排序,依次类推,直至对最主位关键字 K0 排序完成为止。,10.6 基数排序,多关键字的排序,例如:学生记录含三个关键字:系别、班号和班内的序列号,其中以系别为最主位关键字,无序序列,对K2排序,对K1排序,对K0排序,3,2,30,1,2,15,3,1,20,2,3,18,2,1,20,1,2,15,2,3,18,3,1,20,2,1,20,3,2,30,3,1,20,2,

43、1,20,1,2,15,3,2,30,2,3,18,1,2,15,2,1,20,2,3,18,3,1,20,3,2,30,LSD的排序过程如下:,排序过程中不需要根据 “前一个” 关键字的排序结果,将记录序列分割成若干个(“前一个”关键字不同的)子序列。,10.6 基数排序,链式基数排序,假如多关键字的记录序列中,每个关键字的取值范围相同,则按LSD法进行排序时,可以采用“分配-收集”的方法,其好处是不需要进行关键字间的比较。,对于数字型或字符型的单关键字,可以看成是由多个数位或多个字符构成的多关键字,此时可以采用这种“分配-收集”的办法进行排序,称作基数排序法。,10.6 基数排序,链式基数

44、排序,例如:对下列这组关键字209, 386, 768, 185, 247, 606, 230, 834, 539 ,首先按其 “个位数” 取值分别为 0, 1, , 9“分配” 成 10 组,之后按从 0 至 9 的顺序将 它们 “收集” 在一起;,然后按其 “十位数” 取值分别为 0, 1, , 9 “分配” 成 10 组,之后再按从 0 至 9 的顺序将它们 “收集” 在一起;,最后按其“百位数”重复一遍上述操作。,待排序记录以指针相链,构成一个链表;用链表作存储结构的基数排序设置10个队列,fi和ei分别为第i个队列的头指针和尾指针,“分配” 时,按当前“关键字位”所取值,将记录分配到

45、不同的 “链队列” 中,每个队列中记录的 “关键字位” 相同;,“收集”时,按当前关键字位取值从小到大将各队列首尾相链成一个链表;,对每个关键字位均重复 2) 和 3) 两步。,10.6 基数排序,链式基数排序,在计算机上实现基数排序时,为减少所需辅助存储空间,应采用链表作存储结构,即链式基数排序,具体作法为:,例:,10.6 基数排序,链式基数排序,10.6 基数排序,链式基数排序,10.6 基数排序,链式基数排序,10.6 基数排序,链式基数排序,提醒注意:,“分配”和“收集”的实际操作仅为修改链表中的指针和设置队列的头、尾指针;,2. 基数排序的时间复杂度为O(d(n+rd),其中,分配

46、为O(n);收集为O(rd)(rd为“基”),d为“分配-收集”的趟数。,10.7 各种排序方法的综合比较,一、时间性能,1. 平均的时间性能,基数排序,时间复杂度为 O(nlogn):,快速排序、堆排序和归并排序,时间复杂度为 O(n2):,直接插入排序、起泡排序和 简单选择排序,时间复杂度为 O(n):,10.7 各种排序方法的综合比较,2. 当待排记录序列按关键字顺序有序时,3. 简单选择排序、堆排序和归并排序的时间性能不随记录序列中关键字的分布而改变。,直接插入排序和起泡排序能达到O(n)的时间复杂度; 快速排序的时间性能蜕化为O(n2),10.7 各种排序方法的综合比较,二、空间性能,指的是排序过程中所需的辅助空间大小,1. 所有的简单排序方法(包括:直接插入、起泡和简单选择) 和堆排序的空间复杂度为O(1);,2. 快速排序为O(logn),为递归程序执行过程中,栈所需的辅助空间;,10.7 各种排序方法的综合比较,3. 归并排序所需辅助空间最多,其空间复杂度为 O(n);,4. 链式基数排序需附设队列首尾指针,则空间复杂度为 O(rd)。,

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

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

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


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

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

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