排序算法的稳定性及汇总
稳定性
稳定性是值,相同的值是否能做到相对顺序维持下来,仍然不变。
如果对于基础类型数组的排序,这个稳定性并没什么用。
但是对于两个字段的情况排序,就需要具备稳定性。
比如在按照班级排序的情况,也按照年龄排序。 (通过比较器实现)
各排序算法情况
做到稳定性的
冒泡排序,具有稳定性。相等的时候不交换,即可做到。
插入排序,在往前看的过程中,相等的时候不插就可以做到。
归并排序,可以做到稳定性。merge的时候,遇到相等的先拷贝左边的即可做到。其中小和问题就失去了稳定性,因为采用了先拷贝右边。
技术排序
基数排序
桶排序
做不到稳定性的
选择排序,是做不到稳定性。因为某一个数,发现前面有大于的它的数时,发生交换,这个时候前面那个数如果有跟它相同的数,那么相对位置就改变了。
快排也做不到稳定性。paitition过程就会使得相同的数位置交换。
堆排,做不到稳定性。他是依靠自己的堆结构,这个时候就破坏了稳定性。
总结
集中排序的表格整理
时间 | 空间 | 稳定性 | |
---|---|---|---|
选择排序 | O(N2) | O(1) | × |
冒泡排序 | O(N2) | O(1) | √ |
插入排序 | O(N2) | O(1) | √ |
归并排序 | O(N*logN) | O(N) | √ |
快速排序 | O(N*logN) | O(logN) | × |
堆排序 | O(N*logN) | O(1) | × |
- 基于比较的排序,目前无法做到使得时间复杂度低于O(N*logN)
- 时间复杂度在O(N*logN),并且空间复杂度在O(N)以下,还能做到稳定性的,暂时还没有。
常见的坑
- 归并排序是有可能使得额外空间复杂度变成O(1),但是非常难,并且会使得不具备稳定性。这样的话,其效果远不如使用堆排序
- “原地归并排序”,使得空间复杂度变成了O(1),但是时间复杂度会变成O(N2),但是这不如使用插入排序
- 快速排序可以做到稳定性问题,但是会使得空间复杂度变成O(N),可以搜索“0 1 stable sort"
- 有一道题目,奇数放在数组左边,偶数放在右边,并且保持相对的顺序。这个很难做到,快排的partition是基于01标准的,它也可以做到稳定性,但是非常难。
工程上对排序的改进
- 综合几个排序算法,进行一个总体上的复杂度降低。
比如快速排序,但是当小于60的样本,就进行插入排序。这样大样本的数据,基于快排时间复杂度是O(N*logN)的优势,而小样本数据,基于插入常数项低的优势。
- 基于稳定性
系统的Array.sort是怎么实现的,基础类型会采用快速排序,认为稳定性没有用。非基础类型的数据,就会采用归并,为了保持稳定性。
做了一个很复杂的排序策略的。