排序算法简介

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

排序算法

排序算法大致分为两大类,即排序对象全部位于内存的内排序以及排序对象不完全位于内存的外排序。其中又以内排序为排序算法的主要部分,绝大多数的排序算法均适用于内排序。

除了以排序对象是否全部位于内存来划分的两种类型外,排序算法又分为:

1)对待排序对象进行两两比较以确定两对象次序,进而确定整个序列的交换排序

2)将待排序对象中的未排序对象依次插入到已排序好的序列中,此为插入排序

3)将未排序子序列中的最小对象移动到该子序列的最前端并于未排序子序列中

删除此最小对象,这是选择排序

4)利用堆结构实现的堆排序,相当的优秀,对于一般数据有着nlog2(n)的算法复

杂度,并且不需要额外的内存空间

5)十分适合于外排序的归并排序,原理是将待排序序列分割为两两一对的小序

列,对这些小序列进行排序并不断将这些小序列合并,最终获得完整有序序列,

和堆排序一样的算法复杂度,不过需要额外的储存空间。相对于堆排序的优点

是可以处理外排序

以上的5个算法均基于对象关键字大小的比较,以下的两种算法是基于对象关键字

大小的统计比较。

6)比较统计排序,基本思想是对给定的待排序序列中的每一个对象,确定该序列

中键值小于对象键值的对象个数,一旦知道了这个统计信息,那么就可以直接

将对象放到输出序列的正确的位置上了。

7)分布统计排序,是比较统计排序的升级版本,可以获得O(n)的算法复杂度,可

以说是所有算法里面最优的,但是缺点也是很明显,就是对于输入数据结构有

明显的要求和需要额外的内存空间。

下面对上面所述的相关算法进行描述。

一、交换排序

交换排序中最基本简单的就是冒泡排序了,基于冒泡排序的优化算法又有双向冒泡排序。而除了冒泡排序之外,快速排序也是常见的交换排序算法。鉴于冒泡排序太简单了,这里就不打算进行介绍了。

快速排序,是一种效率很好的排序方法,适用于排序问题的规模很大但对于稳定性不做要求的情况。这里的稳定性指的是,对于原序列中拥有相同大小关键字的项,如果在排序后这些项的前后顺序没有变化,那么我们就称该算法为稳定的。

快速排序的设计方法是分冶法,基本思想是:在待排序序列中选择一个对象(比如说第一个对象)作为基准点(pivot),通过将将序列分割为两个子序列(一个子序列的对象都大于基准点,另一个则是小于)来确定基准点的位置。确定了基准点的位置之后对分割开来的两个子序列重复上面的操作(此即为分冶),直到所有的对象都被确定了位置。

举一个例子以较形象的表达这一过程,以数据10、25、25、11、2、5来做例子,其中因为有两个25,所以第2个25以25*表示。

10 25 25* 11 2 5

10 5 25* 11 2 25

10 5 2 11 25* 25

5 2 10 11 25* 25

这里我们可以很清楚的看到,我们对待排序序列中除去pivot的子序列进行相对于pivot的交换排序便可以实现分割序列了。即一开始25大于10而5小于10,所以25和5交换位置,接着是25*和2。最后到2和11时序列已经发生交叉了,所以2以及2之前的所有对象都是小于pivot的,而11和11之后的对象则是都大于pivot的,这样原序列便分割为两个子序列了,把10安插在两个序列中间,那么10便是在其正确的位置上了。然后我们再对这两个子序列在进行相同的操作,直到所有的对象都在其正确的位置上位置。

快速排序的算法复杂度比较复杂,最好情况下的算法复杂度和最坏情况下的算法复杂度相差还是比较大的。最好的情况应该是每一次分割获得的序列都是刚好一半一半对分,这时候有C(n)=C(n/2)+n,也就是说C(n)=nlog2(n),此时的递归二叉树刚好是完全二叉树。最坏的时候,分割得到的两个序列刚好一个是空的,呃,这种情况不会很尴尬么?因为序列本来就是排序好的了。这样子一来,我们可以得到的是C(n)=C(n-1)+n,最终得到的是C(n)=n2,也就是和冒泡排序一样的算法复杂度,而递归二叉树则刚好是一颗退化了的二叉树。

最后考虑一般的情况,也就是说待排序序列是一个随机序列。那么pivot所在位置为s的概率为1/n,于是有C(n)=∑((n+1)+C(s)+C(n-1-s))*1/n,计算得到C(n)≈2n ㏑(n) ≈1.38nlog2(n)。这也就是说,快速排序在一般情况下的算法复杂度仅比最好情况下大38%,所以说快速排序时一种很好的排序方法。在这里,我们使用序列的第一个对象作为pivot,所以如果我们有更好的方法来选择pivot,那么快速排序的效率可能还能更高。

二、插入排序

插入排序简单的有直接插入、折半插入,稍微复杂点的有希尔排序(shell sort)、链表插入。

首先介绍直接插入和折半插入。直接插入,顾名思义,就是把一个个待排序对象给直接插入到已排序的序列中。在插入到已排序序列的过程中,我们很容易可以察觉到插入的方式能够有所不同。是的,如果使用类似牛顿二分法的方式来插入,那么这样的插入排序又称为折半插入。这两种算法都是稳定的。

对于直接插入排序(这里排序时的比较是从已排序序列的第一个对象开始比较,如果是从最后一个对象开始比较那么最坏情况和最好情况刚好反过来,但是算法复杂度并没有变化)而言,最坏情况下是当每次对象插入到已排序序列的时候都插入到最尾端,也就是说序列已经排序好了,这时的算法复杂度为O(n2)。而对于最好的情况,也就是序列刚好是逆序的,这时候算法复杂度为O(n)。而平均而言,一般情况下直接排序的算法复杂度还是O(n2)。对于折半插入而言,因为在插入对象的时候使用了二分法,所以便不存在最好和最坏情况下的算法复杂度的区别。所有情况下的算法复杂度均为θ(nlog2(n))。

从直接排序的特征我们可以看出来,如果插入子序列的对比是从尾部开始的,那么对于有序的序列而言,其排序时相当高效的。而我们知道在快速排序中我们很容易会遇到序列已经倾于排序完的状态,所以我们可以在某些时刻使用排序使得序列快速完成。

希尔排序又称为缩小增量排序法,基本思想是以初始增量gap截取原序列中的对象

相关文档
最新文档