算法入门(十三):排序算法稳定性

177 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第23天,点击查看活动详情

image.png

这个稳定性不是指某些情况下排序时间耗时不一样,是指值相同元素排序完之后能否保证原来的顺序一致(两个1,排完前和排完后相对顺序是固定的)。

image.png

这个稳定性意义针对int类型等基础类型数组没啥意义,因为都是等效的。

但是针对非基础类型,例如一些类的排序就有意义了!举个例子:

image.png

我们针对一个班级学生,先针对age排序,得到从小到大的学生序列,然后需要分班级,按照class进行排序,如果第二轮是稳定性排序的好,得到的class内部也会按照age有序,不会打乱,这就很有用了。

再比如筛选商品,可能你会先按照质量排序,然后再按照价格排序,这样出来的就是便宜且同价格区间按照质量排序的商品。

经典的选择不排序做不到稳定,因为需要跨位置较好,例如下面例子破坏了稳定性:

image.png

而冒泡则可以,只要做到两个值相等时不要进行交换就可以保持稳定性了,如果硬要相等时交换则变成不稳定了,一定程度上也看你代码如何写(当然可以保持更好):

image.png

归并排序也可以做到稳定,关键就是merge成一个的过程如何处理相等,只要两个指针指向数相等时先拷贝左侧到辅助数组就行了:

image.png

但是注意小和问题因为具体原因是从右拷贝到辅助数组的,所以其实丧失了相对顺序

快速排序是不行的,主要就是partition阶段就已经丧失了,主要是因为存在遍历比较和交互的情况,并且是根据一个基准去交换的,下图的3<5就要和6进行swap,这时候就丧失稳定性了:

image.png

而堆排序也是做不到的,因为堆不鸟你是不是稳定的,只是参考自己的堆结构,生成堆结构时候其实就破坏了稳定性,例如下面的heapinsert过程,插入6的时候就需要跟4进行交换,但是他交换是父节点(只跟自己相连的玩,很容易破坏),但是对于实际数组来说是破坏了稳定性:

image.png

而桶排序相关的都是入桶和出桶过程,这个过程本身和比较没关系,而且桶相对次序维持好就是稳定的