以下内容均为个人手打,可能会有一些错误,如果有读者发现有错请指出
无聊的总结了一下排序算法,好像常用的也就那么几种吧(以上分类方式仅个人意见,很多排序方式其实可以同时属于两个分类)
比较排序
这是排序算法中最为常见的一种排序方式。如果没有提到过非比较排序的话,可能不少读者认为排序就是需要比较的。比较排序是我们能够最直观的理解的。这里我就不怎么详细的讲解各种比较排序是如何实现的。(可能之后会补充链接说明)
插入排序
直接插入排序
平均时间复杂度:O(n2)
最优情况:O(n)
最差情况:O(n2)
空间复杂度:O(1)
这样一看,直接插入排序算法其实效率蛮低的
希尔排序
平均时间复杂度:O(n (log n)2)
空间复杂度:O(1)
希尔排序看到了直接插入排序的最优情况,即O(n)的复杂度,通过多次修改间隔,来提高整个序列本身的有序性,从而使得序列不断的接近最优情况来降低时间复杂度。
好像……效率比直接插入排序略高一点,但是感觉还是不够快
交换排序
冒泡排序
平均时间复杂度:O(n2)
最优情况:O(n)
最差情况:O(n2)
空间复杂度:O(1)
理论数据和插入排序一样,惨不忍睹。但实际上,一般情况下,我们伟大的冒泡排序算法实际用时,比直接插入排序还要长……一点……orz
快速排序
为什么快速排序有特写颜色,因为我们通过计算,得到了这样的数据:
平均时间复杂度:O(n log n)
最优情况:O(n)
最差情况:O(n2)
空间复杂度:O(n log 2n)
虽然最差情况下,复杂度没有什么改进,但是,平均情况下,复杂度得到了很大的缩减。快速排序也是我们最常用的(等下会解释为什么是常用的)排序方式
这里提供一个C语言的函数:qsort(?点击可以前往),
qsort函数是C语言中的快排函数,是一个纯粹的快排(如果没有记错的话),手写快排其实……也挺麻烦的(除非你已经会背模版了),也有不少大佬能用3行代码写出快排,做为菜鸡的我表示,能用用qsort就差不多了?
选择排序
时间复杂度:O(n2)
最优情况:O(n2)
最差情况:O(n2)
空间复杂度:O(1)
??!什么东西,这是什么强大的排序方式,拥有如此稳定的复杂度,我验算了3次,确认无误
归并排序
分治法排序,也有人喜欢叫它归并排序、二路归并排序等等。
时间复杂度:O(n log n)
空间复杂度:O(n)
看起来归并排序的效率要略高于快速排序,但是如果真的效率更高的话,为什么C语言只有快排函数,而没有归并排序函数?!所以说,实际上,快速排序的效率要更高一点,而归并排序也是属于较高的
另外,归并排序可以找出序列中逆向对。
树排序
树排序我就真的懒得讲了,总之,主要是懒得写树排序……
二叉树排序
时间复杂度:O(n log n)
最差情况:O(n2)
空间复杂度:O(1)
可以用AVL树来使得时间复杂度趋近于O(n log n)
堆排序
时间复杂度:O(n log n)
最优情况:O(n log n)
空间复杂度:O(1)
比较排序合集!!!
对没错,这里将介绍一种排序方式,一种复杂度能无限趋向于O(n log n)对排序方式:sort
sort是C++的STL库内的一个超级强大的排序函数,大部分情况下,sort会采用快速排序,但是一旦发现快排恶化,复杂度将增大时,sort会及时的插入其他的排序方式,来尽可能的降低复杂度。所以其复杂度将会趋向于O(n log n)比快排的效率还要更高一点
非比较排序
综上,我们看到了很多,几乎所有我们已知的排序方式,但是无论如何,我们好像在为时间复杂度无限趋向于O(n log n)感到骄傲和自豪,问题是,我们可以突破这个限制吗?比如,趋向于O(n)?
这里插入两张来自《算法导论》的照片,书中用决策树来论证了比较排序的最小复杂度。(见书中p107-p108)
简单来说,就是比较排序的本质决定了比较排序的最优情况也要O(n log n)的复杂度。
如果要突破,那就不能是比较排序,即,不能比较
计数排序
假设 n 个输入元素中的每一个都是在0到 k 区间内到一个整数,其中 k 为某个整数。当k=O(n)时,排序的运行时间为O(n)。
计数排序的基本思想是:对每一个输入元素 x ,确定小于 x 的个数。利用这一信息,就可以直接把 x 放到它在输出数组中的位置上了。例如,如果有17个元素小于 x ,则 x 就应该在第18个输出位置上。当有几个元素相同时,这一方案要略做修改。因为不能把它们放在同一个输出位置上。(摘自《算法导论》)
虽然听起来还是用了比较,但是让我们看看伪代码,就能看到这种排序的核心了
COUNTING-SORT(A,B,k)
let C[0..k] be a new array
for i=0 to k
C[i]=0
for j=1 to A.lenth
C[A[j]]=C[A[j]]+1
//C[i] now contains the number of elements equal to i
for i=1 to k
C[i]=C[i]+C[i-1]
//C[i] now contains the number of elements less than or equal to i
for j=A.lenth downto 1
B[C[A[j]]]=A[j]
C[A[j]]=C[A[j]]-1
下面是示意图
通过计算,我们可以得到如下数据:
时间复杂度:O(n+k)
空间复杂度:O(n+k)
当k的值较小时,比如10、100的时候,复杂度可以说直接降到O(n)!
反之,则时间复杂度虽然小了,但是空间复杂度将会大大增加。
桶排序
是一种比较老式的排序方式,这里就不再过多说明了,给出复杂度:O(n*k)