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