我很好奇,为什么稳定性在排序算法中是否重要?
答案 0 :(得分:270)
如果具有相同键的两个对象在排序输出中以与要排序的输入数组中出现的相同顺序出现,则排序算法被称为稳定。一些排序算法本质上是稳定的,如插入排序,合并排序,冒泡排序等。并且一些排序算法不是,如堆排序,快速排序等。
背景:“稳定”排序算法按顺序保存具有相同排序键的项目。假设我们有一个5个字母的单词列表:
peach
straw
apple
spork
如果我们只按每个单词的第一个字母对列表进行排序,那么稳定排序会产生:
apple
peach
straw
spork
在不稳定排序算法中,straw
或spork
可以互换,但在稳定版本中,它们会保持相同的相对位置(即,{ {1}}在输入中出现在straw
之前,它也出现在输出中的spork
之前。
我们可以使用这个算法对单词列表进行排序:按列5进行稳定排序,然后是4,然后是3,然后是2,然后是1。 最后,它将被正确排序。说服自己。 (顺便说一句,该算法称为基数排序)
现在回答你的问题,假设我们有一个名字和姓氏的清单。我们被要求“按姓氏排序,然后先排序”。我们可以先按名字排序(稳定或不稳定),然后按姓氏进行稳定排序。在这些排序之后,列表主要按姓氏排序。但是,如果姓氏相同,则对名字进行排序。
您不能以相同的方式堆叠不稳定的排序。
答案 1 :(得分:34)
一个稳定的排序算法是按照它们在输入中出现的相同顺序对相同元素进行排序的算法,而不稳定排序可能不满足该情况。< / p>
稳定的排序算法:
不稳定的排序算法:
答案 2 :(得分:17)
排序稳定性意味着具有相同键的记录在排序之前和之后保留其相对顺序。
因此,只有当您解决的问题需要保留相对顺序时,稳定性才会起作用。
如果你不需要稳定性,你可以使用库中的快速,内存啜饮算法,比如heapsort或quicksort,并忘掉它。
如果你需要稳定性,那就更复杂了。稳定算法比不稳定算法具有更高的大O CPU和/或内存使用率。因此,当您拥有大型数据集时,您必须在击败CPU或内存之间进行选择。如果你受到CPU和内存的限制,那就有问题了。一个好的折衷稳定算法是二叉树排序; Wikipedia article基于STL实现了一个非常简单的C ++实现。
您可以通过将原始记录号添加为每条记录的最后一个键来将不稳定算法变为稳定算法。
答案 3 :(得分:14)
稳定性很重要的原因有几个。一个是,如果两个记录不需要通过交换来交换,则可能导致内存更新,页面被标记为脏,并且需要重新写入磁盘(或其他慢速介质)。
答案 4 :(得分:14)
这取决于你做了什么。
想象一下,你有一些带有名字和姓氏字段的人物记录。首先,按名字对列表进行排序。如果您使用按姓氏的稳定算法对列表进行排序,则您将拥有按名字和姓氏排序的列表。
答案 5 :(得分:4)
如果具有相同键的两个对象在排序输出中以与输入未排序数组中出现的顺序相同的顺序出现,则称排序算法是稳定的。一些排序算法本质上是稳定的,如插入排序,合并排序,冒泡排序等。并且一些排序算法不是,如堆排序,快速排序等。
然而,任何不稳定的给定排序算法都可以修改为稳定。可以使用排序算法使其保持稳定的特定方式,但是通常,通过改变键比较操作可以将任何不稳定的基于比较的排序算法修改为稳定,使得两个键的比较将位置视为具有相同键的对象的因子。
参考文献: http://www.math.uic.edu/~leon/cs-mcs401-s08/handouts/stability.pdf http://en.wikipedia.org/wiki/Sorting_algorithm#Stability
答案 6 :(得分:3)
我知道有很多答案,但对我来说,this answer,Robert Harvey,更清楚地总结了一下:
稳定排序是保留输入集的原始顺序的排序,其中[unstable]算法不区分两个或更多项。
答案 7 :(得分:1)
如果你假设你正在排序的只是数字,只有它们的值识别/区分它们(例如具有相同值的元素是相同的),那么排序的稳定性问题是没有意义的。
但是,排序中具有相同优先级的对象可能是不同的,有时它们的相对顺序是有意义的信息。在这种情况下,不稳定排序会产生问题。
例如,您有一个数据列表,其中包含在游戏中用Level [L]清除迷宫的所有玩家的时间成本[T]。 假设我们需要根据他们清理迷宫的速度对玩家进行排名。但是,还有一条额外的规则:无论花费多长时间,清洁迷宫级别的玩家总是拥有更高的等级。
当然,您可以尝试将配对值[T,L]映射到实数[R],其中某些算法遵循规则,然后按[R]值对所有玩家进行排名。
但是,如果稳定排序是可行的,那么您可以简单地按[T](首先是更快的玩家)然后按[L]对整个列表进行排序。在这种情况下,按照他们清理的迷宫级别对玩家的相对顺序(按时间成本)不会改变。
PS:当然,排序两次的方法不是解决特定问题的最佳方法,但要解释海报的问题应该足够了。答案 8 :(得分:0)
稳定排序将始终在相同输入上返回相同的解决方案(置换)。
例如[2,1,2]将使用稳定排序作为排列[2,1,3]进行排序(首先是索引2,然后是索引1,然后是排序输出中的索引3)这意味着输出总是被洗牌同样的方式。其他不稳定但仍然正确的排列是[2,3,1]。
快速排序不稳定排序和相同元素之间的排列差异取决于选择枢轴的算法。一些实现随机拾取并且可以快速排序,使用相同的算法在相同的输入上产生不同的排列。
稳定的排序算法是必要的确定性。
答案 9 :(得分:0)
需要稳定排序的原因的更多示例。数据库是一个常见的例子。以交易数据库为例,包括姓氏,购买日期,商品编号,价格。假设数据库通常按日期|排序。然后进行查询以按姓氏对数据库进行排序,因为稳定的排序会保留原始顺序,即使查询比较仅涉及姓氏,每个姓氏|的交易也会按时间顺序排列。
一个类似的示例是经典Excel,它一次只能将排序限制为3列。要对6列进行排序,请使用最低3列进行排序,然后使用最高3列进行排序。
稳定的基数排序的经典示例是卡片排序器,用于按基数为10的数字列的字段进行排序。卡从最低有效位到最高有效位排序。每次通过时,都会读取一副纸牌,并根据该列中的数字将其分成10个不同的纸箱。然后,将10个纸箱中的卡片按顺序放回输入料斗(“ 0”个卡片,“ 9”个卡片)。然后,下一列进行另一遍操作,直到所有列都已排序。实际的卡片分类器有10个以上的存储箱,因为卡片上有12个区域,一列可以为空白,并且存在误读的存储箱。要对字母进行排序,每列需要2次通过,数字第一次通过,12 11区域第二次通过。
后来(1937年),出现了一些卡片整理(合并)机器,它们可以通过比较字段来合并两副卡片。输入的内容是两个已经排序的卡片组,一个主卡片组和一个更新卡片组。整理器将两个卡座合并为一个新的资料箱和一个存档箱,可以选择将其用于主副本,以便新主箱仅在有副本的情况下才具有更新卡。这可能是原始(自下而上)合并排序背后思想的基础。