这几天陆陆续续写了几个排序算法,也算是有点收获。现在进行一个总结,从整体上来看这些算法。主要从下列两个方面来对几类排序算法进行分类:
1. 属于内部排序还是外部排序:
要判断一个排序算法属于内部排序还是外部排序,首先要知道内部排序和外部排序的本质区别:
(1)外排序和内排序所涉及的存储器的不同。
一般情况下,内部排序中待排序的文件较小。之所以称为“内”是因为排序是在内存中完成的,文件一般可以一次在内存中排序。而一般外部排序中待排序的文件较大,不存储于内存而存储于外存,且不能一次调用进入内存。对此计算机所采用的策略是:
将文件中的数据分段输入内存,在内存中采用内排序的方法对其进行排序,这样完成排序后的文件成为归并段,然后将其写回外存,这样在外存中形成许多初始归并段。然后对这些归并段采用某种归并方法,进行多遍归并,这样已经排好序的归并段逐渐扩大,最后在外存上形成整个文件的单一归并段,也就完成了这个文件的外排序。
概括来说就是“内排序是在内存上的排序,外排序借助内排序通过嗲偶哦那个间接完成外存上的排序”。
(2)除了存储器的不同,内排序和外排序所采用的存储方式也是不同的。
而对于外排序而言,主要使用两种存储方式。一种是磁盘存储器,一种是磁带存储器。磁盘存储器一般分为硬盘软盘,是一种直接存取的存储设备,即访问存储在磁盘上的文件中的任何一条记录所花费的时间几乎相同,而不是像磁带存储器那样是顺序存储。
(3)内排序和外排序的方法即所采用的策略不同。
内排序主要分为五大类,分别为:
插入排序、选择排序、交换排序、基数排序、归并排序.
其中插入排序又分为直接插入排序、折半插入排序、2一路插入排序、表插入排序和希尔(shell)排序。选择排序又分为简单选择排序、树形选择排序和堆排序。交换排序分为冒泡排序和快速排序。归并排序又分为二路归并排序和多路归并排序。而外排序最常用的是归并排序法。主要分为多路归并排序和置换一选择排序两种,其主要的排序方法结构图如下图1、2所示:
(4)**依据选取排序策略的不同而效益不同。外排序其实是依赖内排序的,具体效益还是看外排序所选择的内排序的策略。
几种内部排序方法的比较如下图:
2.稳定性
从上图可以看出简单插入排序和冒泡排序都是稳定的排序,那么什么是稳定性呢,怎么判断一个排序算法是不是稳定的呢?
稳定性的定义:待排序的记录序列中可能存在两个或两个以上关键字相等的记录。排序前的序列中Ri领先于Rj(即i小于j).若在排序后的序列中Ri仍然领先于Rj,则称所用的方法是稳定的。
通过定义我们可以得出判断排序算法稳定不稳定的关键,就是看排序算法是否改变了相同元素的相对位置。那我们可以判断出稳定的排序有:
插入排序,基数排序,归并排序,冒泡排序,计数排序
不稳定的排序算法有:
快速排序,希尔排序,简单选择排序,堆排序。
接下来一一看这些算法的执行过程是怎样稳定与不稳定的:
冒泡排序:就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,则不会交换;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。
选择排序:是给每个位置选择当前元素最小的,比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二小的,依次类推,直到第n - 1个元素,第n个元素不用选择了,因为只剩下它一个最大的元素了。那么,在一趟选择,如果当前元素比一个元素小,而该小的元素又出现在一个和当前元素相等的元素后面,那么交换后稳定性就被破坏了。比较拗口,举个例子,序列5 8 5 2 9,我们知道第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序不是一个稳定的排序算法。
插入排序:是在一个已经有序的小序列的基础上,一次插入一个元素。当然,刚开始这个有序的小序列只有1个元素,就是第一个元素。比较是从有序序列的末尾开始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置。如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。
快速排序:j下标一直往右走,当a[j] <= a[r]时交换a[i]与a[j],其中r是中枢元素的数组下标,一般取为数组的第n个元素。而i下标的初值是p-1, 标记比a[r]小的最后一个元素,当数组中不存在比a[r]小的元素,则交换a[i+1] 与a[r],完成一趟快速排序。因为限定条件是a[j]<= a[r]时交换,所以两个相等的元素在交换时就会改变次序。所以快速排序不是稳定的。
归并排序是把序列递归地分成短序列,递归出口是短序列只有1个元素(认为直接有序)或者2个序列(1次比较和交换),然后把各个有序的段序列合并成一个有序的长序列,不断合并直到原序列全部排好序。可以发现,在1个或2个元素时,1个元素不会交换,2个元素如果大小相等也没有人故意交换,这不会破坏稳定性。那么,在短的有序序列合并的过程中,稳定是是否受到破坏?没有,合并过程中我们可以保证如果两个当前元素相等时,我们把处在前面的序列的元素保存在结果序列的前面,这样就保证了稳定性。所以,归并排序也是稳定的排序算法。
基数排序 :基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序,最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。基数排序基于分别排序,分别收集,所以其是稳定的排序算法。
桶排序:简单的桶排序,每一个桶内装的都是相同的元素,再按序输出,我们可以认为是稳定的。真正意义上的桶排序,一个桶内既有相同元素,又有不同元素,还要进行一次简单的插入排序,由于插入排序是稳定的,所以桶内排序是稳定的,按序输出也不会改变相同元素的相对次序,所以桶排序也是稳定的。