我将尝试解释这个特定的实现,这是您可能会看到的最简单的实现之一。巧合的是,它也对输入域中允许的数字有严格的限制(由 value 表示MAX
)。
假设我们有 10 个数字的集合。他们共享的一个属性是他们都在域中 [0..5]
{ 3, 2, 2, 5, 1, 4, 0, 2, 5, 4 }
现在,我们创建一个桶的“列表”,其中每个桶代表域中值的集合;不是输入数组。我们的域允许 6 个可能的值,因此我们创建了 6 个存储桶(按“顺序”排列,以防您没有注意到):
0: {}
1: {}
2: {}
3: {}
4: {}
5: {}
现在遍历输入列表,将每个值放入它的存储桶中。从概念上讲,完成后它看起来像这样:
0: {0}
1: {1}
2: {2,2,2}
3: {3}
4: {4,4}
5: {5,5}
现在,只需遍历我们的存储桶列表,然后将每个存储桶中的内容转储回原始容器,替换那里的任何项目。
{ 0, 1, 2, 2, 2, 3, 4, 4, 5, 5}
看起来很简单,是吗?那么为什么不是每个人都这样做呢?好吧,考虑我们扩大问题。代替MAX
6 个可能的值,我们将“值”设为1048576
(2 20如果您想知道的话),但将排序的项目数保持为 10。
现在,给出以下列表:
{ 3, 2, 2, 1048576, 1, 4, 0, 2, 5, 4 }
我们的“桶”列表如下所示:
0: {0}
1: {1}
2: {2,2,2}
3: {3}
4: {4,4}
5: {5}
6: {}
7: {}
.....
1048575: {}
1048576: {1048576}
是的,超过一百万个桶来对十个数字进行排序,这一切都是因为这是我们问题域中允许的最大值。MAX
显然,这对于大天花板是不可行的。将输入范围细分为可管理的集合将是解决此问题的可行解决方案(实际上,这本质上是基数排序的工作方式。
要回答你的最后一组问题,显然如果你有一个相当小的输入域,你将很难在排序速度上击败它。例如,如果我们有一组一千个数字,所有这些数字都在 中[0..9]
,这将是快速的咆哮。再加上几个数量级,根本就没有可比性。然而,你付出的代价,沉重的代价,是一个受限制的输入域。随着域大小的增加,您必须从分桶算法的角度来处理它,并且当您这样做时,您开始朝着 O(NlogN) 的方向前进。鉴于此,有很多算法(堆排序、合并排序、快速排序等)都有自己的一套警告值得考虑。
一个明显“获胜”的地方:假设您必须对一百万个 8 位字符(定义为 中的值[0..255]
)进行排序,您将找不到更快的算法来做到这一点。该域定义明确,非常易于管理,如果使用了适当的“桶”表(字面意思是计数器表),我看不出它被打败了。