为什么quicksort比radix-sort更受欢迎?

时间:2010-08-21 22:24:02

标签: sorting quicksort radix-sort

为什么quicksort(或introsort)或任何基于比较的排序算法比radix-sort更常见?特别是对于数字排序。

Radix-sort不是基于比较的,因此可能比O(n logn)更快。实际上,它是O(k n),其中k是用于表示每个项目的位数。并且内存开销并不重要,因为您可以选择要使用的桶数,并且所需的内存可能少于mergesort的要求。

是否与缓存有关?或者可能在数组中访问整数的随机字节?

6 个答案:

答案 0 :(得分:23)

我想到了两个论点:

  1. Quicksort / Introsort更灵活:

    Quicksort和Introsort可以很好地处理各种数据。排序所需要的只是比较项目的可能性。这对于数字来说是微不足道的,但您也可以对其他数据进行排序。

    另一方面,基数排序只是通过二进制表示来排序。它永远不会将项目相互比较。

  2. 基数排序需要更多内存。

    我见过的所有基数排序实现都使用辅助缓冲区来存储部分排序结果。这增加了排序算法的内存需求。如果你只排序几千字节,这可能不是问题,但如果你进入千兆字节范围,它会产生巨大的差异。

    如果我记得正确的,那么纸上存在基数排序算法。

答案 1 :(得分:11)

一个明显的答案是,您可以使用快速排序(即任何可比较的东西)对任意类型进行排序,而您仅限于使用基数的数字。 IMO快速排序更加直观。

答案 2 :(得分:6)

对于(大多数)现实世界的用例,基数排序较慢。

一个原因是算法的复杂性:

如果项目是唯一的,则k> = log(n)。即使有重复的项目,k< log(n)很小。

另一个是实施:

额外的内存要求(其本身就是一个缺点)会对缓存性能产生负面影响。

我认为可以说很多库,比如标准库,使用Quicksort,因为它在大多数情况下表现更好。 我认为“难以实施”或“不太直观”是主要因素。

答案 3 :(得分:4)

正如Wikipedia

所述
  

与其他排序算法相比,基数排序效率的主题有点棘手,并且存在很多误解。基数排序与基于比较的最佳算法同样有效,效率低或效率更高取决于所做假设的细节。对于具有d个或更少位数的n个键,基数排序效率为O(d·n)。有时d表示为常数,这将使得基数排序比基于最佳比较的排序算法更好(对于足够大的n),这些排序算法都是所需的O(n·log(n))个比较。但是,一般来说d不能算是常数。 特别是,在所有密钥都不同的常见(但有时是隐式)假设下,d必须至少为log(n)的顺序,这最多给出了(密集密集的密钥)时间复杂度O (N·的log(n))即可。这似乎使基数排序与最佳的基于比较的排序一样最有效(如果密钥比log(n)长得多则更糟)。

     

计数器参数是基于比较的算法以比较次数来衡量,而不是实际时间复杂度。在某些假设下,比较将是平均的恒定时间,而在其他假设下则不是。随机生成的密钥的比较平均需要恒定的时间,因为密钥在一半的情况下在第一个位上不同,并且在剩余一半的一半中的第二个位上不同,依此类推,导致平均两个位需要比较。在排序算法中,所做的第一次比较满足随机性条件,但随着排序的进行,比较的密钥显然不再随机选择。例如,考虑自下而上的合并排序。第一遍将比较成对的随机密钥,但最后一遍将比较排序顺序非常接近的密钥。

     

决定因素是密钥的分配方式。基数排序的最佳情况是它们被视为连续的位模式。这将使密钥尽可能短,仍然假设它们是不同的。这使得基数排序为O(n·log(n)),但是基于比较的排序将不那么有效,因为在该假设下比较将不是恒定时间。如果我们改为假设密钥是长度为k·log(n)的位模式,对于常数k> 1和基数2对数,并且它们是均匀随机的,那么基数排序仍然是O(n·log(n)),但基于比较的排序也是如此,因为“额外”长度使得连续的键都是连续的在排序结果中,相比之下,比较是平均的恒定时间。 如果密钥长于O(log(n)),但是随机,那么基数排序将会更差。还有许多其他假设也可以做,而且大多数都需要仔细研究才能制作出来。正确的比较。

答案 4 :(得分:0)

在其他答案中提出的要点是有效的,但就您的关注在几条评论中提到

  

...数字的默认排序算法是使用quicksort实现的。特别是库中的实现......

Quicksort是'安全'的选择。 基于计数排序的基数排序的潜在运行时非常有吸引力,是的,但基数排序很难在恶意/不幸的数据集上表现不佳。如果被排序的键的位数接近被排序的键的数量,则基数排序在n ^ 2上执行,同时具有不可忽略的空间复杂度,并且它往往具有相当高的内置运行时常量而不是数字的内置运行时常量正在排序的键的数字 Mergesort很有吸引力,因为它的行为在某些方面与快速排序类似,后者在每个机会(中位数)选择最佳支点。然而,它具有可观的空间复杂性。它不像radix那样易受恶意/不幸数据的影响,但也没有提供有吸引力的可能的运行时。 除了几乎(或完全)排序的数据集之外,基本的快速排序在大多数数据集上表现都很好,而且空间复杂度很小。
Quicksort的漏洞很容易通过将其转换为随机快速排序来解决。 Radix sort的漏洞通过对正在排序的键设置限制来解决,这本身就会限制库的用户。 Quicksort比小型数据集上的合并更具性能,并且在合并可能更快时可以合理地执行 实现库时,您希望使其具有通用性。以这些示例,一个Web应用程序和一个带有极其受限的微控制器的小型设备为例 Web应用程序需要定期处理恶意数据,并且还有各种各样的需求。具有预处理限制的库不太可能有用。在微控制器的情况下,它可能在空间上受到限制性的限制,并且无法放弃可以保存的最轻微的位。 Quicksort可以节省空间,并且如果出现较慢的情况,它将仅通过常数乘数减慢 总之 -
1.)库通常被编码为尽可能多的通用可用性 2.)周围的良好性能是可以接受的,特别是如果在很多情况下,性能最佳 3.)空间并不总是一个主要问题,但是当它存在时,它通常是明确限制性的

答案 5 :(得分:-3)

Radix sort的效率= O(c.n) 其中c =输入密钥集中的最高位数。 n =输入密钥集中的密钥数。

快速排序的最佳情况= ​​O(n.log n) 其中n =输入密钥集中的密钥数。

假设16个数字按6位数排序:

基数排序= 16 * 6 = 96个时间单位。 快速排序= 16 * 4 = 64个时间单位。

课: 什么时候' c'更少,Radix赢了。当它高时它会失败。快速排序与密钥中的位数无关,这使得它更好,更实用[/ p>]