《各种排序算法的稳定性》由会员分享,可在线阅读,更多相关《各种排序算法的稳定性(5页珍藏版)》请在金锄头文库上搜索。
1、各种排序算法的稳定性各种排序算法的稳定性各种排序算法的稳定性2009-10-21 12:02首先,排序算法的稳定性大家应该都知道,通俗地讲就是能保证排序前 2 个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同。在简单形式化一下,如果 Ai = Aj, Ai 原来在位置前,排序后 Ai 还是要在 Aj 位置前。为了简便下面讨论的都是不降序排列的情形,对于不升序排列的情形讨论方法和结果完全相同。 其次,说一下稳定性的好处。排序算法如果是稳定的,那么从一个键上排序,然后再从另一个键上排序,第一个键排序的结果可以为第二个键排序所用。基数排序就是这样,先按低位排序,逐次按高位排序,低位
2、相同的元素其顺序再高位也相同时是不会改变的。另外,如果排序算法稳定,对基于比较的排序算法而言,元素交换的次数可能会少一些(个人感觉,没有证实)。回到主题,现在分析一下常见的排序算法的稳定性,每个都给出简单的理由。(1)冒泡排序冒泡排序是通过相邻比较、实时交换、缩小范围实现排序的。第 1 次操作 n 个元素,通过相邻比较将 0n-1 中的最大元素交换到位置 n-1 上,第 2 次操作 n-1 个元素,通过相邻比较将0n-2 中的最大元素交换到位置 n-2 上第 n-1 次操作 2 个元素,通过相邻比较将 01 上的最大元素交换到位置 1 上完成排序。在相邻比较时如果两个元素相等,一般不执行交换操
3、作,因此冒泡排序是一种稳定排序算法。(2)选择排序选择排序是通过不断缩小排序序列长度来实现的。第 1 次操作 n 个元素,选择 0n-1 中的最小者交换到位置 0 上,第 2 次操作 n-1 个元素,选择 1n-1 中的最小者交换到位置 1 上第 n-1次操作 2 个元素,选择 n-2n-1 上的最小者交换到位置 n-2 上完成排序。在每次选择最小元素进行交换时,可能破坏稳定性。这种情况可以描述为:约定要发生交换的位置称为当前位置,被交换的位置称为被交换位置,被交换位置上的元素为选中的最小元素。如果当前位置之后和被交换位置之前存在与当前位置相等的元素,执行交换后就破坏了稳定性。如序列 5 8
4、5 2 9, 我们知道第一遍选择第 1 个元素 5 会和 2 交换,那么原序列中 2 个 5 的相对前后顺序就被破坏了,所以选择排序不是一个稳定的排序算法。(3)插入排序插入排序是通过不断扩大排序序列的长度来实现的。第 1次操作 1 个元素,直接放到位置 0 上即可;第 2 次操作 2 个元素,在 01 上为当前元素找到合适位置并插入;第 3 次操作 3 个元素,用在 02 上为当前元素找到合适位置并插入它第 n 次操作 n 个元素,在 0n-1 上为当前元素找到合适位置并插入完成排序。讨论元素的插入过程,假设当前是第 n 次操作,要在 0n-1 上为当前元素寻找合适位置,设置一个工作指针初始
5、化为 n-1,向前移动工作指针直到遇到一个不大于当前元素的元素,就在这个元素的后面插入当前元素,仔细体会这个插入过程,不难理解插入排序是稳定的。(4)快速排序快速排序有两个方向,左边的 i 下标当 ai acenter时一直往左走。如果 i 和 j 都走不动了,这时必有结论 ai acenter = aj,我们的目的是将 a 分成不大于 acenter和大于 acenter的两个部分,其中前者位于左半部分后者位于右半部分。所以如果ij(i 不能等于 j,为什么?)表明已经分好,否则需要交换两者。当左右分好时,j 指向了左侧的最后一个元素,这时需要将acenter与 aj,交换,这个时侯可能会破
6、坏稳定性。这种情形可以这样描述:center 位置之后 j 位置前存在与 j 相等的元素,指向center 与 j 的交换后,稳定性破坏。比如序列为 5 3 3 4 3 8 9 10 11, 现在中枢元素 5 和 3(第 5 个元素,下标从 1 开始计)交换就会把元素 3 的稳定性打乱,所以快速排序是一个不稳定的排序算法。(5)归并排序归并排序是把序列递归地分成短序列,递归出口是短序列只有 1 个元素(认为直接有序)或者 2 个序列(1 次比较和交换),然后把各个有序的段序列合并成一个有序的长序列,不断合并直到原序列全部排好序。可以发现,在 1 个或 2 个元素时,1 个元素不会交换,2 个元
7、素如果大小相等也没有人故意交换,这不会破坏稳定性。那么,在短的有序序列合并的过程中,稳定是是否受到破坏?没有,合并过程中我们可以保证如果两个当前元素相等时,我们把处在前面的序列的元素保存在结果序列的前面,这样就保证了稳定性。所以,归并排序也是稳定的排序算法。(6)基数排序基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序,最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。基数排序基于分别排序,分别收集,所以其是稳定的排序算法。(7)希尔排序(shell)希尔排序是按照不同步长对元
8、素进行插入排序,当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小,插入排序对于有序的序列效率很高。所以,希尔排序的时间复杂度会比 o(n2)好一些。由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以 shell 排序是不稳定的。(8)堆排序我们知道基于 0 序的堆结构,节点 i 的孩子为 2*i+1 和2*i+2 节点,大顶堆要求父节点大于等于其 2 个子节点,小顶堆要求父节点小于等于其 2 个子节点。在一个长为 n 的序列,
9、堆排序的过程是从第 n/2 开始和其子节点共 3 个值选择最大(大顶堆)或者最小(小顶堆),这 3 个元素之间的选择当然不会破坏稳定性。但当为n/2-1, n/2-2, .1 这些个父节点选择元素时,就会破坏稳定性。有可能第 n/2 个父节点交换把后面一个元素交换过去了,而第 n/2-1 个父节点把后面一个相同的元素没有交换,那么这 2 个相同的元素之间的稳定性就被破坏了。所以,堆排序不是稳定的排序算法。通过上面的论述不难发现规律:存在不相邻交换的排序算法一般是不稳定的,相邻交换的排序算法一般是稳定的;对于相邻交换的稳定排序算法,通过控制交换条件可以转换成不稳定排序算法;冒泡、插入、归并和基数排序是稳定的;选择、快速、希尔和堆排序是不稳定的。