常用排序算法_算法数据结构中提到的排序和查找,你真的了解吗? 

先对排序进行分类:插入类排序(直接插入排序、希尔排序、折半插入排序),交换类排序(冒泡排序、快速排序),选择类排序(简单选择排序、堆排序),归并类排序和基数类排序

复杂度比较:

排序算法比较

类型

方法

时间复杂度

空间复杂度

是否稳定

最好情况

最坏情况

平均情况

插入类排序

直接插入排序


O(n)


O(n^2)

O(n^2)

O(1)


希尔排序

和增量函数的选取有关

O(1)


折半插入排序

O(nlog2n)

O(n^2)

O(n^2)

O(1)


交换类排序

冒泡排序


O(n)


O(n^2)

O(n^2)

O(1)


快速排序

O(nlog2n)

O(nlog2n)

O(nlog2n)

O(nlog2n)


选择类排序

简单选择排序

O(n^2)

O(n^2)

O(n^2)

O(1)


堆排序

O(nlog2n)

O(nlog2n)

O(nlog2n)

O(1)


归并类排序

O(nlog2n)

O(nlog2n)

O(nlog2n)

O(n)


基数类排序

O(d(n+r)

O(d(n+r)

O(d(n+r)

O(r)


注:基数排序的复杂度中,r代表关键字的基数,d代表长度,n代表关键字的个数

直接插入排序

算法思想:每趟将一个待排序的关键字按照其值的大小插入到已经排好的部分有序序列的适当位置上,直到所有待排关键字都被插入到有序序列中为止。

折半插入排序

算法思想:以折半查找法查找有序序列上合适的插入位置,再将待排序关键字插入。折半查找法的一个基本条件是序列已经有序,而从直接插入排序的流程中可以看出,每次都是在一个已经有序的序列中插入一个新的关键字,因此可以用折半查找法在这个有序序列中查找插入位置。

适合关键字较多的场景。

希尔排序

算法思想:又叫作缩小增量排序,其本质还是插入排序,只不过是将待排序列按某种规则分成几个子序列,分别对这几个子序列进行直接插入排序,最后将分块逐步扩大。

冒泡排序

算法思想:依序列顺序相互比较,每一趟可以选出无序序列一个最大或者最小的关键字。

快速排序

算法思想:一趟选择当前所有子序列中的一个关键字(通常是第一个)作为枢轴,将子序列中比枢轴小的移到枢轴前,比枢轴大的移到枢轴后:当本趟所有子序列都被枢轴以上述规则划分完毕后会得到新的—组更短的子序列,它们成为下一趟划分的初始序列集。

简单选择排序

算法思想:简单选择排序采用最简单的选择方式,从头至尾扫描序列,选出最小的一个关键字和第一个关键字交换,接着从剩下的关键字中继续这种选择和交换,最终使序列有序。

堆排序

堆的概念

堆是一种数据结构,可以把堆看成一棵完全二叉树,这棵完全二叉树满足:任何一个非叶结点的值都不大于(或不小于)其左右孩子结点的值。若父亲大孩子小,则这样的堆叫作大顶堆;若父亲小孩子大,则这样的堆叫作小顶堆

根据堆的定义知道,代表堆的这棵完全二叉树的根结点的值是最大(或最小)的。

算法思想:

  1. 将一个无序序列调整为一个堆,就可以找出这个序列的最大(或最小)值——根结节点;
  2. 将找出的根节点交换与序列末尾元素进行交换,有序序列关键字增加1个,无序序列中关键字减少1个;
  3. 对交换后的n-1个序列元素进行调整,使其满足大顶堆的性质;
  4. 重复2.3步骤,直至堆中只有1个元素为止

这就是堆排序的思想堆排序中最关键的操作是将序列调整为堆。整个排序的过程就是通过不断调整,使得不符合堆定义的完全二叉树变为符合堆定义的完全二叉树。

归并类排序

算法思想:可以看作一个分而治之的过程(分治法),先将整个序列分为两半,对每一半分别进行归并排序,将得到两个有序序列,然后将这两个序列归并成一个序列即可,主要是递归。

基数类排序

算法思想:每次对集合中所有元素的某一位(d)进行排序,排序的过程包含了分配和收集两种,分配是将元素分配至对应的数字字符组(),收集是将所有组中元素收集到原集合。重复进行分配和收集直至集合中的每一位元素都排序完成。

适合关键字较多的场景。

此外还有外部排序 ,所谓外部排序,即对外存中的记录进行排序(相对于内部排序而言)。有了内部排序算法,为什么还要外部排序?因为外存中记录规模太大,内存放不下。外部排序可以概括为一句话:将内存作为工作空间来辅助外存数据的排序。最常用的是归并排序和堆排序,不需要一次性将记录读入内存中。

总结

时间复杂度:快些以 nlog2n的速度归队。其中,“快”指快速排序,“些”指希尔排序(发音近似)【归并了解即可】,“归”指归并排序,“队”指堆排序(谐音),这4种排序的平均复杂度都是O(nlog2n);基数排序为O(d(n+r),其他都是O(n^2)。

  • 时间复杂度的变化:直接插容易插变成O(n),起泡起得好变成O(n),所谓“容易插”或“起得好”都是指初始序列已经有序。

空间复杂度:快速排序为O(log2n),归并排序为O(n),基数排序为O(r),其他都是o(1)。

稳定性:“快些选好朋友”。这里,“快”指快速排序,“些”指希尔排序,“选”指简单选择排序,“堆”指堆排序,这4种是不稳定的,其他自然都是稳定的。

其他:

  1. 经过一趟排序,能够保证一个关键字到达最终位置,这样的排序是交换类的那两种(起泡、快速)和选择类的那两种(简单选择、堆);
  2. 排序算法的关键字比较次数和原始序列无关—简单选择排序和折半插入排序;
  3. 排序算法的排序趟数和原始序列有关—交换类(冒泡、快速)的排序。

关于稳定性

稳定性的定义

      假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。

稳定性的意义
稳定性对复杂对象的某一个数字属性排序毫无意义。除非要排序的内容是一个复杂对象的多个数字属性,且其原本的初始顺序存在意义,那么我们需要在二次排序的基础上保持原有排序的意义,才需要使用到稳定性的算法。例如要排序的内容是一组原本按照价格高低排序的对象,如今需要按照销量高低排序,使用稳定性算法,可以使得相同销量的对象依旧保持着价格高低的排序展现,只有销量不同的才会重新排序。(当然,如果需求不需要保持初始的排序意义,那么使用稳定性算法依旧将毫无意义)。