📜  排序算法的稳定性

📅  最后修改于: 2021-05-04 10:18:22             🧑  作者: Mango

当我们拥有可能存在重复键的键值对(例如,人名作为键,其详细信息作为值)时,稳定性至关重要。我们希望按键对这些对象进行排序。

它是什么?
如果两个具有相等关键字的对象在出现在要排序的输入数组中的对象在排序后的输出中以相同的顺序出现,则该排序算法被认为是稳定的。

形式上的稳定性可以定义为:
A成为一个数组,让<对以下元素进行严格的弱排序A
如果满足以下条件,则排序算法是稳定的:
i < j\:\:and\:\:A[i]\equiv A[j]\:\:implies\:\:\pi (i) < \pi (j)
在哪里\pi是排序排列(排序动作A[i]定位\pi(i) )
非正式地,稳定性是指等效元素在分类后保留其相对位置。

稳定性排序

我们是否关心像整数数组这样的简单数组?
当相等的元素无法区分时(例如整数),或更普遍地说,以整个元素为键的任何数据,稳定性都不是问题。如果所有键都不相同,那么稳定性也不是问题。

一个有用的例子
考虑以下学生姓名及其各自的班级数据集。

\\ (Dave, A)\\ (Alice, B)\\ (Ken, A)\\ (Eric, B)\\ (Carol, A)

如果仅根据名称对数据进行排序,则结果数据集也不太可能根据部分进行分组。

\\ (Alice, B)\\ (Carol, A)\\ (Dave, A)\\ (Eric, B)\\ (Ken, A)

因此,我们可能也必须再次排序才能明智地获得学生名单。但是这样做的话,如果排序算法不稳定,我们可能会得到如下结果:

\\ (Carol, A)\\ (Dave, A)\\ (Ken, A)\\(Eric, B)\\(Alice, B)

现在,数据集是根据部分而不是名称进行排序的。
在按名称排序的数据集中,元组(Alice, B)以前(Eric, B) ,但由于排序算法不稳定,因此会丢失相对顺序。
另一方面,如果我们使用稳定的排序算法,则结果将是-

\\ (Carol, A)\\ (Dave, A)\\ (Ken, A)\\(Alice, B)\\(Eric, B)

在这里,保持了不同元组之间的相对顺序。可能的情况是,相对顺序以不稳定的顺序维护,但这极不可能。

哪些排序算法是稳定的?
一些排序算法本质上是稳定的,例如冒泡排序,插入排序,合并排序,计数排序等。
基于比较的稳定排序(例如合并排序和插入排序)可通过确保以下各项来保持稳定性:
元素A[j]来之前A[i]当且仅当A[j] < A[i] ,这里的i,j是索引, i < j
自从i<j ,相对顺序被保留if A[i]\equiv A[j] IE A[i]来之前 A[j]
其他非基于比较的排序(例如计数排序)通过确保以相反的顺序填充已排序数组来保持稳定性,以使具有等效键的元素具有相同的相对位置。
诸如Radix Sort之类的某些种类依赖于另一种种类,唯一的要求是另一种种类应该稳定。

哪些排序算法不稳定?
通过同时考虑元素的位置,可以使快速排序,堆排序等保持稳定。进行此更改的方式不会影响性能,并且会占用一些额外的空间(可能\theta(n)

我们可以使任何排序算法稳定吗?
任何给定的不稳定算法都可以修改为稳定的。可以使用特定的排序算法来使其稳定,但是通常,可以通过更改键比较操作将本质上不稳定的任何基于比较的排序算法修改为稳定,以便将两个键的比较视为位置。具有相同键的对象的系数。

参考:
http://www.math.uic.edu/~leon/cs-mcs401-s08/handouts/stability.pdf
http://en.wikipedia.org/wiki/Sorting_algorithm#稳定