1.比较排序:快速排序、堆排序、归并排序、插入排序等。基于比较的排序时间复杂度下限为O(n log n)
2 线性时间排序:计数排序、基数排序、桶排序等
3 稳定排序
--快速排序
在主元元素a[r]和a[i+1]交换的时候,很有可能把前面的元素的稳定性打乱,比如序列为3 3 5 4 3 8 9 10 1,主元为1,第一轮划分后为1 3 3 5 4 3 8 9 10 3,把最开始的3换到了最后,元素3的稳定性打乱,所以快速排序是一个不稳定的排序算法,不稳定发生在中枢元素和a[i+1] 交换的时刻。所以快速排序是不稳定的。
---插入排序
插入排序是在一个已经有序的小序列的基础上,一次插入一个元素。当然,刚开始这个有序的小序列只有1个元素,就是第一个元素。比较是从有序序列的末尾开始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置。如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。
--堆排序
比如:3 27 36 27,
如果堆顶3先输出,则,第三层的27(最后一个27)跑到堆顶,然后堆稳定,继续输出堆顶,是刚才那个27,这样说明后面的27先于第二个位置的27输出,所以堆排序是不稳定的。
--规并排序
归并排序是把序列递归地分成短序列,递归出口是短序列只有1个元素(认为直接有序)或者2个序列(1次比较和交换),然后把各个有序的段序列合并成一个有序的长序列,不断合并直到原序列全部排好序。可以发现,在1个或2个元素时,1个元素不会交换,2个元素如果大小相等也没有人故意交换,这不会破坏稳定性。那么,在短的有序序列合并的过程中,稳定是是否受到破坏?没有,合并过程中我们可以保证如果两个当前元素相等时,我们把处在前面的序列的元素保存在结果序列的前面,这样就保证了稳定性。所以,归并排序也是稳定的排序算法。
--基数排序
基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序,最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。基数排序基于分别排序,分别收集,所以其是稳定的排序算法。
--计数排序(稳定的)
4 原地排序
排序算法 | 平均时间 | 最差时间 | 稳定度 | 额外空间 | 备注说明 |
冒泡排序 | O(n2) | O(n2) | 稳定 | O(1) | n小时较好 |
选择排序 | O(n2) | O(n2) | 不稳定 | O(1) | n小时较好 |
插入排序 | O(n2) | O(n2) | 稳定 | O(1) | n小时较好 |
归并排序 | O(nlogn) | O(nlogn) | 稳定 | O(n) | n大时较好 |
快速排序 | O(nlogn) | O(n2) | 不稳定 | O(logn) | n大时较好 |
堆排序 | O(nlogn) | O(nlogn) | 不稳定 | O(1) | n大时较好 |
计数排序 | O(n) | O(n) | 稳定 | O(n+k) | 输入序列限制 |
基数排序 | O(n) | O(n) | 稳定 | O(n+k) | 输入序列限制 |
桶排序 | O(n) | O(n) | 稳定 | O(n) | 输入序列限制 |
1,排序的稳定性
简单的来说就是:能保证两个相等的数的前后序列在排序完成后序列位置相同,那么我们就说它是稳定的。
Ai = Aj,排序前:Ai在Aj之前 排序后:Ai还在Aj之前,那么当前这个算法是有效的
冒泡排序:
类似与水中上升的气泡越来越小,将小的往后调,比较相邻的两个元素。所以,如果两个元素相等,我想,我们是
不会无聊的再去将他们再去交换一遍;如果序列中有两个相等的元素,那么经过交换,相等的元素也是会相邻的,也
是不会交换的。所以说:具体的序列位置还是没有进行变化,所以是一种稳定的排序算法
选择排序:
选择排序的核心是给每一个位置找当前序列中最小的,如:(从小到大)从n个数中找最小的放在第一个位置,然
后在后面的n - 1个数中找最小的放在第二个位置,后面的同理;但是此刻,大家可不要混淆了,我们找最小的跟冒
泡还是不一样的,大部分的情况下,我们是通过一个变量:min来跟后面的数值进行比较,而冒泡是通过相邻的进
行比较找到小的值。关于选择排序的稳定性:
我们选择排序:4,8,4,2,5
可以很容易的看到:选择排序不是一个稳定的排序算法
插入排序:
简单的说:就是在一个已经有序的小序列上,一次只插入一个元素,当然,刚开始的有序的小序列只有一个元素
即就是待排的第一个元素,比较的过程是从有序序列的末尾开始比较,如果比末尾的大,直接放在后面;如果比末
尾的小,那么比他还大的位置,将其后整体后移;如果遇见一个相等的,那么将其放在后面
如:插入排序:4,8,3,4,2,5
同理:插入排序是一个稳定的排序算法
快速排序:
基本思想就是:先从数列中取出第一个数作为基准,分区的过程中,将比基准大的数放在它的右边,将比基准小
或者跟基准一样的放在基准的左边,然后在对左右的分区过程重复上面的分区过程,直至上面的这些分区出现一
个数。
如:快速排序:5,3,4,6,7,3,2
一次排序结果:
可知:快速排速也不是一个稳定的排序算法
归并排序:
归并排序是把序列递归的分成极短的序列,递归的结束条件就是只有一个元素,我们可以将其当作一个有序的序列
然后把各个有序的短序列,合并成一个有序的长序列,不断的合并,知道所有的元素都是有序的,即可。
可以理解的是:当只有一个元素的两个短序列,如果在数值相等的条件下合并的话,那么也不会无聊的再去交换去
浪费时间了,
如:归并排序:3,3,2
同理:归并排序也是稳定的排序算法
基数排序:
核心思想就是:通过“分配”和“收集”的过程来实现分配
通常来说,我们常用的一种方法:先按照低位来排序,然后收集,然后在对次低位进行排序,收集,直到最高位
基数排序:10,12,31,24,12
如:
所以可知:基数排序也是稳定的
希尔排序:
希尔排序是插入排序的一种,是按照不同步长对元素进行插入排序,当刚开始的时候,步长最大,那么插入排序的
元素个数最少,速度也很快,当元素基本有序的情况下,步长很小,插入排序对有序的序列效率很高。上面,我们
也知道,插入排序是一种稳定的算法,但是:对于希尔排序而言,一趟是经过多次插入的,我们不能保证顺序。
希尔排序:
可知:希尔排序并不稳定。
堆排序:
关于堆排序,可以知道父结点为i(数组从0开始)的话,那么左孩子的节点就是2i + 1, 右孩子的节点就是2i + 2
,当然,有大小顶堆之分,大顶堆要求父节点大于左右孩子节点,小顶堆要求父节点小于左右孩子节点,当建堆完
成之后,我们需要将堆顶的元素跟最后一个叶子节点进行交换,循环建堆过程即可。
关于堆排序的稳定性:3,2,5,4,2,6
所以:我们总结一下
稳定的排序:冒泡,插入排序,归并排序,基数排序
不稳定的排序:选择,快速排序,希尔排序,堆排序
2,内排序和外排序
根据在排序过程中待排序的记录是不是全部被放置在内存中,排序分为:内排序和外排序
内排序是在整个过程中,待排序的所有记录全部被放置在内存中。
外排序是由于排序的记录个数太多,不能同时放置在内存,整个排序过程需要在内外存之间多次交换数据才能
进行。
对于内排序而言:
排序算法的性能主要是受3个方面的影响:
1,时间性能
排序是数据处理中经常执行的一种操作,往往属于系统的核心部分,因此排序算法的时间开销是衡量其好坏
的最重要的标志。在内排序中,主要进行两种操作:比较和移动
所以:一个高效率的内排序算法应该是具有尽可能少的比较次数和移动次数。
2,辅助空间
评价排序算法的另一个主要标准是执行算法所需要的辅助存储空间,辅助存储空间是除了存放待排序所占用的
存储空间之外,执行算法所需要的其他存储空间
3,算法的复杂性
一个算法复杂性的高低好坏,取决于运行该算法所需要的计算机的资源的多少,所需的资源越多,那么说
明我们算法的复杂性越高
各个算法的时间复杂度及其空间复杂度(图片来自:http://blog.sina.com.cn/s/blog_77795cad01011txt.html)