如何在线性排序下考虑铲斗排序?

时间:2013-05-23 12:16:00

标签: algorithm sorting bucket-sort

我想探讨一下有关Bucket sort的分析,如下所示。
可以通过多种方式实现Bucket排序。其中一些如下 类型1:
如果我们知道我们的元素范围进行排序,我们可以设置 桶对于每个可能的元件,而只是抛元件成其相应的水桶。然后我们 清空为了桶,其结果是一个排序列表。 在执行这个算法,我们可以很容易地使用数组来代表我们的桶,在此,值 每个数组索引将代表在对应的桶元件的数量。如果我们有一个整数 在范围[0..max]上,然后我们设置一个(max + 1)个整数的数组,并将所有值初始化为 零。然后,我们通过排序的数组进行顺序,读取每个元素的值,去 到水桶阵列中的对应的索引,并且递增的值存在。

时间:O(N)
空间:O(1)
类型2:

示例:按年龄对人数排序 年龄与排序的任意整数有些不同。因此它有一个小范围[0-150](所有人的年龄都在0到150之间)。因此,最快的排序方法是分配151个链接列表(让我们称之为桶),并根据他/她的年龄将每个人的数据结构放入存储桶中:

时间:O(N + K)
空间:O(N + K)

类型3(类型2的变体,如Wikepedia所示)

函数nextSort是一个排序函数,用于对每个桶进行排序。如果使用的插入排序比最差的将是O(n ^ 2)或将使用合并排序,以便我可以保持稳定性而不是O(nlgn)。

  • 问题:
    1>如何将其视为线性排序,是因为类型1还是类型2? 2>如果我像WIkepedia一样使用Type 3哪种排序有效排序每个桶?
    我知道在实践中使用插入排序的原因是我们希望存储桶很小,而对于小型列表,插入排序比其他任何东西都快。即使实现合并排序或快速排序,当列表变得足够小时(例如,大约20项左右),也会使用插入排序。
    3>对于类型3,在此基础上我可以决定铲斗的范围?
    这一点非常重要,因为如果您尝试使用大量存储桶执行存储桶排序(例如远大于n),则运行时可能会占用扫描所有存储桶以查找实际使用的存储桶所需的时间,即使其中大部分都是空的。

我做了分析基于:
Wikepedia
How could the complexity of bucket sort is O(n+k)?
Design and Analysis of Algorithms Lecture notes for January 23, 1996
http://www1bpt.bridgeport.edu/~dichter/lilly/bucketsort.htm
http://cs.nyu.edu/courses/fall02/V22.0310-002/lectures/lecture-23.html
How is the complexity of bucket sort is O(n+k) if we implement buckets using linked lists?
What is the worst case complexity for bucket sort?

3 个答案:

答案 0 :(得分:3)

类型1:
您描述的第一种类型不是真正的桶排序。它实际上是计算排序或密钥索引计数。虽然它被认为是铲斗排序的变种。原因是因为你实际上只计算每个密钥的出现次数,而不是将密钥本身存储在桶中。

参考:http://en.wikipedia.org/wiki/Counting_sort
参考:http://www.cs.princeton.edu/courses/archive/spr13/cos226/demo/51DemoKeyIndexedCounting.pdf

  

空间:O(1)
  我们可以为每个可能的元素设置存储桶,

这不矛盾吗?您将为每个可能的元素声明存储区并仍保留O(1)? ;)

如果希望算法稳定,则也不能覆盖输入数组。所以在实践中你需要空间要求n + k:

  • 长度为'n'的输出数组(基本上与输入数组相同)
  • 'k'水桶

如果检查伪代码以计算排序,您会注意到最后一个循环再次遍历输入数组以查看每个元素需要去的位置。按照它们在输入数组中出现的顺序执行此操作,您将获得稳定的排序。

PS:请记住,您不一定要排序整数。如果输入是A-Z之间的字符数组,您也可以使用此算法。

类型2:

  

所以最快的排序方法是分配151个链表(让我们称之为桶)   并根据他/她的年龄将每个人的数据结构放入桶中:

这可能是最简单的方法,因为你可以很容易地找到所需的桶,但它不一定是最快的方式;)。例如,另一种可能性是每10年创建一个桶。

00 - 09
10 - 19
20 - 29
...

当你想在桶中插入东西时,你可以这样做:

  • 在存储桶上进行二进制搜索(例如LinkedList)以找到正确的位置
  • 插入元素

这样,您之后也不需要对存储桶进行排序,因为所有内容都已经排序。不是说这是一个好主意,只是指出了可能性。 ;)

问题:
1)简单地说;这是一种线性排序,因为它需要线性时间来排序。类型1和类型2都采用O(n + k)。因为bucket sort不使用诸如quicksort,bubblesort等元素之间的比较,所以它不受O(n log n)下限的约束。请记住,O符号并不能保证速度,它可以保证增长速度。 如果您的输入大小从“N”加倍到“2N”,则线性时间算法将比例如像冒泡排序的O(n ^ 2)算法更好地应对它。 ;)

2)插入排序确实对小数组有效,这主要是它被选择的原因。 +它稳定的事实。因为如果你不使用稳定的算法来对桶本身进行排序,整个算法(桶排序)将不稳定。

3)很难说。这取决于我认为的数据。如果你必须排序100万个32位整数,你就不会为它们创建2 ^ 32个桶。在这种情况下,看看其他算法(例如LSD Radix排序)可能会很好,这将基本上创建9个桶(每个数字1个)。

答案 1 :(得分:1)

当每个桶按线性时间排序时,桶分类是线性时间。 “类型1”和“类型2”都是线性时间,因为每个桶中的所有值都成比例相等,不需要进一步排序。

后两个问题的答案是在实践中起作用的。通常,标准库排序的编写者已确定插入排序的适当截止值。我认为存储桶排序的性能在很大程度上取决于所讨论的数据和内存子系统。

答案 2 :(得分:0)

您描述的类型1和类型2实际上是相同的,意味着您具有范围。是的,在那种情况下,它是线性的时间复杂度,因为不需要在每个存储桶内进行进一步排序。每个存储桶都包含一种类型的值。