为什么快速排序(或introsort)或者任何基于比较的排序算法比基数排序更为常见呢?尤其是对于数字的排序。
基数排序不是基于比较的,因此可能比O(nlogn)更快。实际上,它的时间复杂度是O(kn),其中k是用于表示每个项目的位数。而且内存开销并不重要,因为您可以选择要使用的桶的数量,并且所需的内存可能小于归并排序的要求。
这与缓存有关吗?或者与访问数组中的随机字节有关吗?
为什么快速排序(或introsort)或者任何基于比较的排序算法比基数排序更为常见呢?尤其是对于数字的排序。
基数排序不是基于比较的,因此可能比O(nlogn)更快。实际上,它的时间复杂度是O(kn),其中k是用于表示每个项目的位数。而且内存开销并不重要,因为您可以选择要使用的桶的数量,并且所需的内存可能小于归并排序的要求。
这与缓存有关吗?或者与访问数组中的随机字节有关吗?
我想到了两个观点:
快速排序/内省排序更灵活:
快速排序和内省排序可用于所有类型的数据。对于排序,您只需要比较项的可能性。这在数字方面很简单,但您也可以对其他数据进行排序。
另一方面,基数排序仅通过其二进制表示对事物进行排序。它从不将项目相互比较。
基数排序需要更多内存。
我见过的所有基数排序实现都使用辅助缓冲区来存储部分排序结果。这增加了排序算法的内存需求。如果您只排序几千字节,那可能不是问题,但如果您进入吉巴字节范围,则会产生巨大差异。
如果我没记错的话,有一种原地基数排序算法存在于论文中。
基数排序在(大多数)实际应用场景下速度较慢。
一个原因是算法的复杂性:
如果项目是唯一的,则k >= log(n)。即使存在重复项,k< log(n)的问题集也很小。
另一个原因是实现:
额外的内存需求(本身就是一个缺点),会对缓存性能产生负面影响。
我认为可以肯定地说,许多库,例如标准库,使用快速排序,因为它在大多数情况下表现更好。 我不认为“难以实现”或“不太直观”是主要因素。
一个显而易见的答案是,您可以使用快速排序(即任何可比较的内容)对任意类型进行排序,而使用基数排序只能限制在数字上。并且我认为,快速排序更加直观。
如在维基百科上提到的
基数排序与其他排序算法的效率问题有些棘手,也容易引起很多误解。无论是基数排序是否比最佳比较排序算法同样有效、更有效还是不如它,都取决于所做假设的细节。对于具有 d 位或更少数字的 n 个键,基数排序的效率为 O(d·n)。有时会将 d 视为常量,这会使基数排序(对于足够大的 n)优于所有需要 O(n·log(n)) 次比较的最佳比较排序算法。然而,在一般情况下,d 不能被视为常量。特别是,在普遍(但有时隐含的)假设下,所有键都是不同的,则 d 必须至少是 log(n) 的级别,这在最好情况下(密集排列键)给出了时间复杂度 O(n·log(n))。 这似乎使基数排序最多与最佳比较排序一样有效(如果键比 log(n) 长得多,则更劣)。快速排序是“安全”的选择。基于计数排序的基数排序的潜在运行时间非常有吸引力,但是基数排序易受恶意/不幸数据集的影响。如果被排序键的位数接近被排序键的数量,基数排序的性能将达到n^2,而且空间复杂度也相当高,除了被排序键的位数之外,它往往具有相当高的内置运行时常量。
归并排序之所以有吸引力,是因为它的行为在某些方面类似于每次都选择最佳枢轴(中位数)的快速排序。然而,它具有可观的空间复杂度。它不像基数排序那样容易受到恶意/不幸的数据影响,但也没有提供有吸引力的可能运行时间。
基本快速排序在大多数数据集上表现非常好,除了几乎(或完全)排序的数据集之外,并且具有微小的空间复杂度。
快速排序的漏洞可以通过将其转换为随机化快速排序来轻松处理。基数排序的漏洞可以通过对被排序键施加限制来解决,这将从根本上限制库的用户。在小型数据集上,快速排序比归并排序更具性能,并且在归并排序可能更快的情况下表现合理。
在实现库时,您希望使其具有通用性。以这些示例为例,一个Web应用程序和一个具有极限制微控制器的小型设备。
Web应用程序需要定期处理恶意数据,并且具有各种需求。具有预条件限制的库不太可能有用。在微控制器的情况下,它可能会在空间上受到限制,并且无法放弃可以节省的最小位。快速排序节省空间,如果出现较慢的情况,则只会通过常数乘数完成。
总之 -
1.) 库通常编码为尽可能通用的可用性
2.) 在所有方面都具有良好的性能是可以接受的,特别是如果在许多情况下,它是最佳性能
3.) 空间并不总是主要问题,但当它是时,通常明确地限制
基数排序的效率 = O(c.n) 其中c = 输入关键字集中最高位数。 n = 输入关键字集中的关键字数量。
快速排序的最佳情况 = O(n. log n) 其中n = 输入关键字集中的关键字数量。
假设要对16个数字进行排序,每个数字有6位:
基数排序 = 16 * 6 = 96 时间单位。 快速排序 = 16 * 4 = 64 时间单位。
教训: 当'c'较小时,基数排序胜出。当它很高时,它就会输掉。快速排序不受关键字位数的影响,这使它更好、更实用。
n
相当大的情况下能够在合理的时间内完成。我们并不真正关心 96/64 时间单位的情况。 - francox9