结论
排序算法的稳定性与具体的实现有关,一个不稳定的排序算法,通过额外的时间或空间,可以转变为稳定的;一个稳定的排序算法,也可以转变为不稳定的。这与大多数课本的说法有所不同,课本对每种算法的稳定性都给出了肯定唯一的答案,其实都隐含了各自的前提条件。
下面举例说明这个问题,排序是从小到大排序。
冒泡排序的稳定性
冒泡排序,每次都从第0个元素开始遍历,比较当前元素arr[i]和下一个元素arr[i+1],如果arr[i]>arr[i+1],那么交换二者,i增加1,继续类似的比较。
冒泡排序过程中,存在相邻元素的交换,如果交换的条件是:前者>后者,那么就是稳定的。如果交换条件是:前者>=后者,就不是稳定的。
例如 […, 1a, 1b, …],不满足第一种交换条件,则不进行交换,则1a会一直在1b前面,稳定。满足第二种条件,则会交换,交换后,1b在1a前面,不稳定。
选择排序的稳定性
选择排序,假设数组分为两部分,左边有序的部分,和右边无序的部分。每次都从无序序列中找到一个最小的元素,放到有序列表的末尾。问题是【如何将无序列表中最小的元素放到有序列表的末尾?】
举例:
[1, 2, 3, 4, 5, 10a, 8, 10b, 7, 6]
前面的[1, 2, 3, 4, 5]是有序列表,后面的[10a, 8, 10b, 7, 6]为无需列表,找到最小的元素为6,如何放到10a的位置呢?
第一种办法:将6与10a进行交换,得到 [1, 2, 3, 4, 5, 6, 8, 10b, 7, 10a]
可见,10a与10b的顺序不对了,不稳定!这是课本采用的方法,也是课本认为选择排序不稳定的原因。
第二种办法:
tmp=6
for i in range(9, 4, -1):
arr[i] = arr[i-1]
arr[4] = tmp
得到 [1, 2, 3, 4, 5, 6, 10a, 8, 10b, 7]
可见是稳定的,但这一轮,耗费了O(n)的时间复杂度。
第三种办法:新开辟数据,就没这么多问题了,耗费额外O(n)的空间。