为什么要区分稳定和不稳定排序

本文探讨了排序算法中的稳定性概念,稳定排序算法在相等元素间保持原有顺序,如冒泡排序、插入排序和归并排序。通过举例说明,当需要对多个关键字进行排序时,稳定排序可以保留先前排序的信息,确保在后续排序中相同元素的顺序不受影响。对于如订单排序或考试成绩排名等场景,稳定排序能够确保正确满足特定优先级的排序需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


对于排序算法,相信你一定不陌生吧!如我们常见的几大经典排序:

冒泡排序插入排序选择排序快速排序归并排序堆排序等等。


这些排序算法中,性能、内存消耗各有优劣,同时也各有各的适用场景,而我们也不能仅仅从时间复杂度和空间复杂度的优劣去评断一个排序算法的好与坏,比如冒泡排序插入排序,两者的时间复杂度均是O(n²),空间复杂度也都是O(1),但是插入排序却更常用,而且在很多实际场景中,执行效率更高,至于原因,你可以思考一下,此文暂不做讨论。


而排序算法中,除了时间复杂度和空间复杂度,还有着一个我们比较常关注的性质:稳定性

我们这里简单描述一下什么是排序算法的稳定性:

对于某一种排序算法,如果待排序的序列中存在值相等的元素,经过排序之后,相等元素之间原有的先后顺序保持不变,那么就说这个排序算法是稳定的。

而上面所提到的几种排序算法中,冒泡排序、插入排序、归并排序属于稳定排序,选择排序、快速排序、堆排序属于不稳定排序。


简单举个例子:

假设对数组[3, 2, 2, 5, 1, 4]进行递增排序,数组中有两个元素是相等的即2,为方便标识,我们先用2'表示第二个2,即原数组为:[3, 2, 2', 5, 1, 4]。

  • 如果使用稳定排序,那么排序后有且仅有一种结果:[1, 2, 2', 3, 4, 5]。

  • 如果使用不稳定排序,那么排序后,可能会出现这种结果:[1, 2', 2, 3, 4, 5]


排序的稳定性很好去理解,也很容易去分析。但是你有没有想过:

既然所有的排序算法排出来的结果都是有序的,为什么还要区分稳定性和不稳定性的算法呢?



我们用下面一个场景来说明。


假设有一万条订单记录,要对这些订单进行一个排序,要求按照金额有小到大的顺序排列,如果订单金额相同,则按照下单时间的先后进行排列。

假设订单数据为:

在开始进行排序时,有一点先要弄明白:像这种存在需要对多个关键字进行排序的,每一次排序只能基于其中某一个且仅一个关键字进行排序,无法对多个关键字同时排序。之所以提这一点,是为了避免有人拿Java的比较器Comparator做对比,那根本是两码事。

而对于需要针对多个关键字排序的情况,优先级最高的要放在最后排才行,比如这里先按照金额大小排序,在金额大小相同的情况下,再按照下单时间排序,优先级最高的就是金额,那么就应该最后再排金额。如果先排金额,在排序后,如果有金额相同的,再排下单时间,那么最后的结果就是以下单时间的先后为准了,你好好想一想,是不是这么回事?

好,那我们进行排序,先对下单时间进行排序,得到的结果为:

得到这个结果后,我们再对金额进行一次排序就OK了,但是这里为了达到需求要求的效果,即金额相同的,下单时间早的要排在前面,则第二次排序只能用稳定排序。如果使用不稳定排序,第二次按照金额排序后,得到的结果虽然在金额上是有序的,但下单时间上就不一定有序了,换一种说法就是:第一次按照订单时间排序的结果,没有被第二次按照金额排序利用上,先看图:

使用稳定排序后的结果:

这样子你应该明白了吧,如果使用不稳定排序,那么第二次排序后的结果,就可能不符合要求,不稳定排序会改变相同元素的原有顺序。在这个场景中,不稳定排序就可能会把金额均是30的原有顺序改变了(注意哦,这个顺序是已经按照下单时间排好序的结果),从而导致最终的排序结果对于金额相同的,没有按照时间先后来排序。但是这种问题,使用稳定排序就不会出现。


所以,现在你明白了吧,之所以区分排序的稳定性和不稳定性,是有它的实际应用场景的,它的意义在于:

在需要对多个(也意味着多次)具有优先级的关键字进行排序的场景下,稳定排序能利用上一次排序的结果服务于本次排序,从而保证对于值相同的元素的两次排序结果相同。


用这个场景来解释就是:

第一次排序先对下单时间进行排序,得到的排序结果中,两个金额为30的记录在下单时间上已经是有序的了;然后第二次排序对金额进行排序,由于使用了稳定排序,两个金额为30的记录的顺序就不会被改变了,这就相当于第一次排序的结果被第二次排序利用上了。



如果你还是不能够完全理解,再举一个实际场景:


对考生的成绩进行排名,如果总分相同的,则按照语文分数高低排,如果语文分数还相同的,继续按照数学分数高低排。

看到这个例子,你是否恍然大悟了呢?

在这个例子中,排序的优先级是:总分 > 语文 > 数学,如果使用稳定排序,我们就能得到预期且是正确的结果;如果使用不稳定排序,就有可能会出现,对于总分相同的,语文分数较低的就排在了更前面,这个结果对于成绩排名,就不是正确的。


这就是稳定排序的实际应用场景,对于某些场景,不稳定排序得到结果可能是不正确的。


THE END

### 稳定排序与非稳定排序的概念 在数据结构中,排序算法依据其处理相同键值记录的方式被区分稳定排序稳定排序。 #### 稳定排序的特点 对于具有相等键值的元素,在经过排序之后这些元素之间的相对次序保持不变,则该排序称为稳定排序。例如,在一个包含多个字段的对象数组上先按次要关键字排序再按主要关键字排序时,如果采用的是稳定排序算法,那么当两个对象的主要关键字相同时,它们会按照之前由次要关键字决定的位置排列[^1]。 ```python class Record: def __init__(self, primary_key, secondary_key): self.primary_key = primary_key self.secondary_key = secondary_key records = [ Record('A', 2), Record('B', 1), Record('C', 2), # Same as first record's secondary key but different primary keys. ] # Assuming a stable sort on `secondary_key` followed by another stable sort on `primary_key`. sorted_records = sorted(sorted(records, key=lambda r: r.secondary_key), key=lambda r: r.primary_key) for rec in sorted_records: print(f"{rec.primary_key}:{rec.secondary_key}") ``` 这段代码展示了如何利用两次稳定的内部排序来实现多级排序的效果。 #### 非稳定排序的特点 而非稳定排序则不然;它并不保证拥有相同键值的数据项之间原有的先后关系得以保留。这意味着即使原始序列中有若干个相同的数值,在完成排序操作后这些重复元素可能出现任意顺序。这通常发生在那些通过比较相邻元素并可能跨越较大距离移动元素从而破坏原有顺序的高效排序方法里,比如快速排序或堆排序[^2]。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yeqiu1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值