在最坏的情况下不能在嵌入式系统中使用合并排序
需要 O(n) 的空间复杂度。
您可能对 C++ 中的 stable_sort 函数感兴趣。它尝试为常规合并排序分配额外空间,但如果失败,它会执行时间复杂度较低的就地稳定合并排序(n * ((log n)^2) 而不是n * (log n))。如果您可以阅读 C++,则可以查看您最喜欢的标准库中的实现,否则我希望您可以在与语言无关的术语中找到解释的细节。
有大量关于就地稳定排序(尤其是就地合并)的学术文献。
所以在 C++ 中,经验法则很简单,“如果需要稳定的排序,请使用 std::stable_sort,否则使用 std::sort”。 Python 再次让它变得更容易,经验法则是“使用sorted”。
一般来说,你会发现很多语言都有相当聪明的内置排序算法,而且你大部分时间都可以使用它们。您很少需要实现自己的才能击败标准库。如果您确实需要实现自己的,那么没有什么可以替代教科书,用尽可能多的技巧实现一些算法,并针对特定对它们进行相互测试> 您担心需要击败库函数的情况。
您在回答这个问题时可能希望得到的大多数“显而易见”的建议已经被纳入一种或多种常见编程语言的内置排序功能中。但要回答您的具体问题:
哪种排序算法最适合按字母顺序对名称进行排序?
基数排序可能会优于标准比较排序,如 C++ sort,但如果您对名称使用“正确”的排序规则,这可能是不可能的。例如,“McAlister”过去的字母顺序与“MacAlister”相同,“St. John”的字母顺序与“Saint John”相同。但后来程序员出现了,他们只想按 ASCII 值排序,而不是编写许多特殊规则,因此大多数计算机系统不再使用这些规则。我发现星期五下午是这种功能的好时机;-) 如果您对“规范化”名称的字母而不是实际名称进行排序,您仍然可以使用基数排序。
英语以外的其他语言的“正确”排序规则也很有趣。例如在德语中,“Grüber”类似于“Grueber”,因此出现在“Gruber”之后但在“Gruhn”之前。在英语中,“Llewellyn”这个名字出现在“Lewis”之后,但我相信威尔士语(使用完全相同的字母表但不同的传统排序规则)它在前面。
因此,谈论优化字符串排序比实际操作要容易。 “正确”排序字符串需要能够插入特定于语言环境的排序规则,如果您放弃比较排序,则可能需要重新编写所有排序代码。
哪种排序算法最适合排序较少的整数?
对于少量的小值,可能是计数排序,但是当数据变得足够小(20-30 个元素)时切换到插入排序的 Introsort 非常好。当数据不是随机的时,Timsort 特别好。
哪种排序算法最适合排序较少但范围可能较大(98767 - 6734784)的整数?
大范围排除了计数排序,因此对于少量范围广泛的整数,Introsort/Timsort。
哪种排序算法最适合对数十亿个整数进行排序?
如果您所说的“十亿”是指“太多而无法放入内存”,那么这会稍微改变游戏规则。可能您想将数据分成适合内存的块,Intro/Tim 对每个块进行排序,然后进行外部合并。如果您在 64 位机器上对 32 位整数进行排序,则可以考虑计数排序。
哪种排序算法最适合在空间和时间都受到约束的嵌入式系统或实时系统中进行排序?
可能是自我介绍。
对于有些排序的东西,插入排序很好。
没错,Timsort 利用了同样的情况。
对几乎排序的数组应用快速排序是愚蠢的。
错误。没有人使用最初由 Hoare 发布的普通 QuickSort,您可以做出更好的枢轴选择,使杀手案例比“排序数据”更不明显。为了彻底处理不良情况,有 Introsort。
堆排序在 O(nlogn) 时很好,但不稳定。
没错,但 Introsort 更好(而且也不稳定)。
合并排序不能用于嵌入式系统,因为在最坏的情况下它需要 O(n) 的空间复杂度。
通过像std::stable_sort 那样允许稍微慢一些的就地合并来处理这个问题。