简单排序:冒泡排序、插入排序、选择排序
八种排序稳定性比较:
选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,
冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法。
排序算法稳定性的分析:
稳定性的含义:通俗地讲就是能保证排序前 2 个相等的数其在序列的前后位置顺序和排序
后它们两个的前后位置顺序相同。在简单形式化一下,如果 Ai = Aj, Ai 原来在位置前,排序后
Ai 还是要在 Aj 位置前。
稳定性的好处:排序算法如果是稳定的,那么从一个键上排序,然后再从另一个键上排序,
第一个键排序的结果可以为第二个键排序所用。基数排序就是这样,先按低位排序,逐次按高
位排序,低位相同的元素其顺序再高位也相同时是不会改变的。另外,如果排序算法稳定,对
基于比较的排序算法而言,元素交换的次数可能会少一些(个人感觉,没有证实)。
回到主题,现在分析一下常见的排序算法的稳定性,每个都给出简单的理由。
(1)冒泡排序
冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交
换也发生在这两个元素之间。所以,如果两个元素相等,我想你是不会再无聊地把他们俩交换
一下的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时
候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。
(2)选择排序
选择排序是给每个位置选择当前元素最小的,比如给第一个位置选择最小的,在剩余元素
里面给第二个元素选择第二小的,依次类推,直到第 n-1 个元素,第 n 个元素不用选择了,因
为只剩下它一个最大的元素了。那么,在一趟选择,如果当前元素比一个元素小,而该小的元
素又出现在一个和当前元素相等的元素后面,那么交换后稳定性就被破坏了。比较拗口,举个
例子,序列 5 8 5 2 9, 我们知道第一遍选择第 1 个元素 5 会和 2 交换,那么原序列中 2 个 5 的
相对前后顺序就被破坏了,所以选择排序不是一个稳定的排序算法。
(3)插入排序
插入排序是在一个已经有序的小序列的基础上,一次插入一个元素。当然,刚开始这个有
序的小序列只有 1 个元素,就是第一个元素。比较是从有序序列的末尾开始,也就是想要插入
的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到
找到它该插入的位置。如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相
等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后
的顺序,所以插入排序是稳定的。
(4)快速排序
快 速 排 序 有 两 个 方 向 , 左 边 的 i 下 标 一 直 往 右 走 , 当 a[i] <= a[center_index] ,其 中
center_index 是中枢元素的数组下标,一般取为数组第 0 个元素。而右边的 j 下标一直往左走,
当 a[j] > a[center_index]。如果 i 和 j 都走不动了,i <= j, 交换 a[i]和 a[j],重复上面的过程,直到
i>j。 交换 a[j]和 a[center_index],完成一趟快速排序。在中枢元素和 a[j]交换的时候,很有可能
把前面的元素的稳定性打乱,比如序列为 5 3 3 4 3 8 9 10 11, 现在中枢元素 5 和 3(第 5 个元素,
下标从 1 开始计)交换就会把元素 3 的稳定性打乱,所以快速排序是一个不稳定的排序算法,不