排序方法的总结

一、排序方法分类

1、按照操作方式不同可以分为:

1)插入排序:直接插入排序、希尔排序

2)交换排序:冒泡排序、快速排序

3)选择排序:直接选择排序、堆排序

4)归并排序:归并排序

5)分配排序:桶排序、基数排序

2、按照平均时间不同可以分为:

1)平方阶(O(n2))排序

一般称为简单排序,例如直接插入、直接选择和冒泡排序;

2)线性对数阶(O(nlgn))排序

如快速、堆和归并排序;

3)O(n1+£)阶排序

£是介于0和1之间的常数,即0<£<1,如希尔排序;

4)线性阶(O(n))排序

如桶、箱和基数排序。

3、按照是否涉及数据的内、外存交换分为:

1)内部排序

在排序过程中,若整个文件都是放在内存中处理,排序时不涉及数据的内、外存交换,则称之为内部排序(简称内排序)

2)外部排序

若排序过程中要进行数据的内、外存交换,则称之为外部排序

外部排序指的是大文件的排序,面试的时候,面试官喜欢问,给你一个非常非常大的文件(比如1T),一行一个数(或者一个单词),内存最多只有8G,硬盘足够大,CPU很高级……然后要你给这个文件里面的数据排序。你要怎么办?

这其实就要用到外部排序。就是说要借助外存储器进行多次的内/外存数据的交换,因为内存不足以加载所有的数据,所以只能一部分一部分地加载。

二、排序算法的操作方法与存储方式

1、排序算法的基本操作

大多数排序算法都有两个基本操作:

  • 比较两个关键字的大小。
  •       改变指向记录的指针或移动记录本身。

注意:
     第(2)种基本操作的实现依赖于待排序记录的存储方式。

2、待排文件的常用存储方式

     1)以顺序表(或直接用向量)作为存储结构

排序过程:对记录本身进行物理重排,即通过关键字之间的比较判定,将记录移到合适的位置。

2)以链表作为存储结构

排序过程:无须移动记录,仅需修改指针。通常将这类排序称为链表(或链式)排序。

3)以顺序的方式存储待排序的记录,但同时建立一个辅助表(如包括关键字和指向记录位置的指针组成的索引表)

排序过程:只需对辅助表的表目进行物理重排(即只移动辅助表的表目,而不移动记录本身)。适用于难于在链表上实现,且仍需避免排序过程中移动记录的排序方法。

三、排序算法的性能分析

1、稳定性

      在待排序的文件中,若存在多个关键字相同的记录,经过排序后这些具有相同关键字的记录之间的相对次序保持不变,该排序方法是稳定的

     若具有相同关键字的记录之间的相对次序发生变化,则称这种排序方法是不稳定的

注意
     排序算法的稳定性是针对所有输入实例而言的。即在所有可能的输入实例中,只要有一个实例使得算法不满足稳定性要求,则该排序算法就是不稳定的。

2、影响排序效果的因素

因为不同的排序方法适应不同的应用环境和要求,所以选择合适的排序方法应综合考虑下列因素:
①待排序的记录数目n;
②记录的大小(规模);
③关键字的结构及其初始状态;
④对稳定性的要求;
⑤语言工具的条件;
⑥存储结构;
⑦时间和辅助空间复杂度等。

3、一些常见算法的性能比较

下面是一个总的表格,大致总结了我们常见的所有的排序算法的特点。

排序法 最好时间 平均时间 最差情形 稳定度 额外空间 备注
冒泡 O(n) O(n2) O(n2) 稳定 O(1) n小时较好
交换   O(n2) O(n2) 不稳定 O(1) n小时较好
简单选择 O(n2) O(n2) O(n2) 不稳定 O(1) n小时较好
直接插入 O(n) O(n2) O(n2) 稳定 O(1) 大部分已排序时较好
基数   O(logRB) O(logRB) 稳定 O(n)

B是真数(0-9),

R是基数(个十百)

Shell O(n) O(nlogn) O(ns) <s<2 不稳定 O(1) s是所选分组
快速 O(nlogn) O(nlogn) O(n2) 不稳定 O(logn) n大时较好
归并 O(nlogn) O(nlogn) O(nlogn) 稳定 O(n) n大时较好
O(nlogn) O(nlogn) O(nlogn) 不稳定 O(1) n大时较好

四、排序算法的选择

1、不同条件下,排序方法的选择

(1)若n较小(如n≤50),可采用直接插入或直接选择排序。
    当记录规模较小时,直接插入排序较好;否则因为直接选择移动的记录数少于直接插人,应选直接选择排序为宜。
(2)若文件初始状态基本有序(指正序),则应选用直接插人、冒泡或随机的快速排序为宜;
(3)若n较大,则应采用时间复杂度为O(nlgn)的排序方法:快速排序、堆排序或归并排序。
    快速排序是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;
    堆排序所需的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况。这两种排序都是不稳定的。
    若要求排序稳定,则可选用归并排序。但本章介绍的从单个记录起进行两两归并的  排序算法并不值得提倡,通常可以将它和直接插入排序结合在一起使用。先利用直接插入排序求得较长的有序子文件,然后再两两归并之。因为直接插入排序是稳定的,所以改进后的归并排序仍是稳定的。

2、针对各个排序算法的选择分析

1)快速排序(QuickSort)

从本质上来说,快速排序是归并排序的就地版本。

快速排序比大部分排序算法都要快。尽管我们可以在某些特殊的情况下写出比快速排序快的算法,但是就通常情况而言,没有比它更快的了。快速排序是递归的,对于内存非常有限的机器来说,它不是一个好的选择。

2)归并排序(MergeSort)

归并排序先分解要排序的序列,从1分成2,2分成4,依次分解,当分解到只有1个一组的时候,就可以排序这些分组,然后依次合并回原来的序列中,这样就可以排序所有数据。合并排序比堆排序稍微快一点,但是需要比堆排序多一倍的内存空间,因为它需要一个额外的数组。

3)堆排序(HeapSort)

堆排序适合于数据量非常大的场合(百万数据)。

堆排序不需要大量的递归或者多维的暂存数组。这对于数据量非常巨大的序列是合适的。比如超过数百万条记录,因为快速排序,归并排序都使用递归来设计算法,在数据量非常大的时候,可能会发生堆栈溢出错误。

4)Shell排序(ShellSort)

Shell排序比冒泡排序快5倍,比插入排序大致快2倍。Shell排序比起QuickSort,MergeSort,HeapSort慢很多。但是它相对比较简单,它适合于数据量在5000以下并且速度并不是特别重要的场合。它对于数据量较小的数列重复排序是非常好的。

5)插入排序(InsertSort)

插入排序通过把序列中的值插入一个已经排序好的序列中,直到该序列的结束。插入排序是对冒泡排序的改进。它比冒泡排序快2倍。一般不用在数据大于1000的场合下使用插入排序,或者重复排序超过200数据项的序列。

6)冒泡排序(BubbleSort)

冒泡排序是最慢的排序算法。在实际运用中它是效率最低的算法。它通过一趟又一趟地比较数组中的每一个元素,使较大的数据下沉,较小的数据上升。它是O(n^2)的算法。

7)交换排序(ExchangeSort)和选择排序(SelectSort)

这两种排序方法都是交换方法的排序算法,效率都是 O(n2)。在实际应用中处于和冒泡排序基本相同的地位。它们只是排序算法发展的初级阶段,在实际中使用较少。

8)基数排序(RadixSort)

基数排序和通常的排序算法并不走同样的路线。它是一种比较新颖的算法,但是它只能用于整数的排序,如果我们要把同样的办法运用到浮点数上,我们必须了解浮点数的存储格式,并通过特殊的方式将浮点数映射到整数上,然后再映射回去,这是非常麻烦的事情,因此,它的使用同样也不多。而且,最重要的是,这样算法也需要较多的存储空间。

参考:http://space.itpub.net/15203236/viewspace-616582

五、各个算法的链接

插入排序:http://www.cnblogs.com/aoguren/p/3289499.html

交换排序:http://www.cnblogs.com/aoguren/p/3287367.html

选择排序:http://www.cnblogs.com/aoguren/p/3292895.html

归并排序:http://www.cnblogs.com/aoguren/p/3293202.html

分配排序:http://www.cnblogs.com/aoguren/p/3294222.html

原文地址:https://www.cnblogs.com/aoguren/p/3294293.html