转【算法之常用排序算法(二)】常用排序算法性能比较,及常见面试题


各种排序方法的性能比较:

排序法

平均时间

最坏情况

最好情况

稳定度

额外空间

备注

1.直接插入

O(n2)

O(n2)

O(n)

稳定

O(1)

大部分已排序时较好(简单)

1.希尔

O(nlogn)

O(nlogn)

与步长相关

不稳定

O(1)

n小时较好(较复杂)

2.冒泡

O(n2)

O(n2)

O(n)

稳定

O(1)

n小时较好(简单)

2.快排

O(nlogn)

O(n2)

O(nlogn)

不稳定

O(logn)

n大时较好,基本有序时反而不好(较复杂)

3.直接选择

O(n2)

O(n2)

O(n2)

不稳定

O(1)

n小时较好(简单)

3.堆排序

O(nlogn)

O(nlogn)

O(nlogn)

不稳定

O(1)

n大时较好(较复杂)

4.归并

O(nlogn)

O(nlogn)

O(nlogn)

稳定

O(n)

n大时较好(较复杂)

基数

O(d(n+r))

O(d(n+r))

O(d(n+r))

稳定

O(r)

d为位数,r为基数(较复杂)

计数

O(n+k)

O(n+k)

O(n+k)

稳定

O(n+k)

优于比较排序法,0~k为数值范围

桶排序

O(n+c)

O (nlogn):所有的元素落到一个桶中

O(n)

稳定

O(n+m)

n为数的个数,m为桶数

c = n*(logn-logm)

桶越多,效率越高,n=m,达到O(n),但是占用很大的空间,桶内可用快排等

 

(一)基于比较的排序算法:

1、第一类——插入排序法:直接插入排序,希尔。以及不常见的Tree sort、Library sort、Patience sorting 。

2、第二类——交换排序法:冒泡、快排(由冒泡改进而来)。以及不常见的鸡尾酒排序、奇偶排序、梳排序、Gnome sort 。

3、第三类——选择排序法:直接选择、堆排序。

4、第四类——归并排序法:归并排序。以及不常见的Strand sort。

(二)非基于比较的排序算法:

上表中蓝色粗体标识:基数、计数、桶排序。

 

性能分析及选择排序方法的考量:

 

O(n^2)的分析:

在数据规模较小时(9W之内),直接插入(略微好于简单选择)、简单选择差不多。当数据较大时,冒泡排序算法的时间代价是最昂贵的。 另外,普通排序算法基本上都是相邻元素进行比较,因此O(N^2)的排序基本都是稳定的。

 

O(nlogn)的分析:

其中快速排序无疑是最优秀的。其次是归并排序和希尔排序,堆排序稍微差一些。

 

 

先进算法分析:

(1) 就时间性能而言,希尔排序、快速排序堆排序和归并排序都是较为先进的排序方法。耗时远小于O(N^2)级别的算法。

(2) 先进算法之中,快排的效率是最高的。但其缺点十分明显:在待排序列基本有序的情况下,会蜕化成起泡排序,时间复杂度       接近 O(N^2)。

(3) 希尔排序的性能让人有点意外,这种增量插入排序的高效性完全说明了:在基本有序序列中,直接插入排序绝对能达到令人      吃惊的效率。但是希尔排序对增量的选择标准依然没有较为满意的答案,要知道增量的选取直接影响排序的效率。

(4) 归并排序的效率非常不错,在数据规模较大的情况下,它比希尔排序和堆排序都要好。

(5)堆排序在数据规模较小的情况下还是表现不错的,但是随着规模的增大,时间代价也开始和shell和归并两种排序拉开距离。

(6) 多数先进排序都因为跳跃式的比较,降低了比较次数,但是也牺牲了排序的稳定性。

总的来说,并不存在“最佳”的排序算法。必须针对待排序列自身的特点来选择“良好”的算法。

 

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

 

1.插入、冒泡排序的速度较慢,但参加排序的序列局部或整体有序时,这种排序能达到较快的速度。

反而在这种情况下,快速排序反而慢了。

2.当n较小时,对稳定性不作要求时宜用选择排序,对稳定性有要求时宜用插入或冒泡排序。

3.若待排序的记录的关键字在一个明显有限范围内时,且空间允许是用桶排序。

4.当n较大时,关键字元素比较随机,对稳定性没要求宜用快速排序。

5.当n较大时,关键字元素可能出现本身是有序的,对稳定性有要求时,空间允许的情况下,宜用归并排序。

6.当n较大时,关键字元素可能出现本身是有序的,对稳定性没有要求时宜用堆排序。


下面有一些指导性的意见:

(1) 数据规模很小,而且待排序列基本有序的情况下,选择直接插入排序或冒泡排序绝对是上策。不要小看它O(N^2)级别。

(2) 数据规模不是很大,完全可以使用内存空间。而且待排序列杂乱无序(越乱越开心),快速排序永远是不错的选择,当然付出log(N)的额外空间(为栈所需的辅助空间)是值得的。

(3) 海量级别的数据,必须按块存放在外存(磁盘)中。此时的归并排序是一个比较优秀的算法,在数据规模较大的情况下,它比希尔排序和堆排序都要好。

 

 

 


常考问题:

1.简单选择排序、堆排序和归并排序的时间性能不随记录序列中关键字的分布而改变。 

2.直接插入排序在某一趟结束后未必能选出一个元素放在其最终位置;但是堆排序、冒泡(在首趟即可确定最大值和最小值)、快排可以。

3.已知数组中的每个元素距离最终位置不远,采用直接插入排序最节省时间。

4.直接选择排序关键字比较次数和记录的初始排列顺序无关,都为n(n-1)/2。

5.对n个元素执行快排,在进行第一次划分时,关键字的比较次数总是n-1。

来源:http://blog.csdn.net/cangchen/article/details/44962973