有人可以解释这种桶排序的实现如何工作?

时间:2013-02-26 06:27:42

标签: c++ sorting

我很难理解存储桶排序的基本概念,我希望有人可以向我详细说明排序算法的作用以及它如何在O(N中完成所需的结果(排序内部容器) ) 时间。此外,由于这似乎相当快,其他排序算法(如冒泡,插入或选择)有哪些优势可以说服人们在桶排序中使用它们?

这是我在网上找到的算法的实现。如果有人可以在他们的解释中提到这一点,我将非常感激。

void binsort(std::vector<std::size_t>& A){
    std::vector<std::vector<std::size_t>> B(MAX + 1);
    for(std::size_t i = 0; i < SIZE; ++i){
        B[A[i]].push_back(A[i]);
    }
    std::size_t current = 0;
    for(std::size_t i = 0; i < MAX; ++i){
        for(auto item : B[i]){
            A[current++] = item;
        }
    }
}

感谢您的帮助。

4 个答案:

答案 0 :(得分:4)

我会尝试解释这个具体的实现,这是你可能会看到的最简单的实现之一。不巧的是,输入域中也允许使用允许数字的严格限制(由值MAX表示)。

假设我们有10个数字的集合。他们共享的一个属性是它们都在域[0..5]

{ 3, 2, 2, 5, 1, 4, 0, 2, 5, 4 }

现在,我们创建一个桶的“列表”,其中每个桶代表来自域的值的集合; 输入数组。我们的域允许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]中的值),您将找不到更快的算法来执行此操作。域名定义明确,非常易于管理,如果使用了适当的“桶”表(字面意思是计数器表),我看不出它被击败了。

答案 1 :(得分:0)

这是Wikipedia提供的解释。我希望这就足够了。

  

Bucket sort或bin sort是一种排序算法   将数组划分为多个存储区。然后是每个桶   单独排序,使用不同的排序算法,或者   递归地应用桶排序算法。它是一个   分布排序,并且是最基本排序的表亲   重要的数字味道。 Bucket sort是一个概括   鸽笼排序。由于桶排序不是比较排序,因此Ω(n   log n)下限不适用。计算复杂性   估计涉及桶的数量。

Bucket sort的工作原理如下:

  1. 设置一个最初为空的“桶”数组。
  2. 分散:遍历原始数组,将每个对象放入其存储桶中。
  3. 对每个非空桶进行排序。
  4. 收集:按顺序访问存储桶并将所有元素放回原始数组中。

答案 2 :(得分:0)

给出的解释非常酷。那么,如果我们有负数,我们如何处理这种情况呢?一种方法是为负数保留一个单独的桶列表。

想象一下这个数据集:{ - 5,-6,5,3,6,-4}

所以这里我们的&#34;桶列表&#34;如下:

清单1:

0: {0}
1: {0}
2: {0}
3: {1}
4: {0}
5: {1}
6: {1}

Bucket list 2:

-1: {0}
-2: {0}
-3: {0}
-4: {1}
-5: {1}
-6: {1}

因此,如果我们的案例只涉及整数,那么我们的存储桶列表甚至不必包含其他列表。它们可以只是列表。

答案 3 :(得分:0)

要处理负数的情况,您可以选择最小的负数,并将该数字添加到数组中的每个元素。 {-5,-6,5,3,6,-4}具有最小元素-6。将绝对值-6添加到数组中。 数组现在为{1,0,11,9,12,2}然后使用存储桶数组对其进行排序,该数组变为{0,1,2,9,11,12},并为每个数据库添加-6最终结果{-6,-5,-4,3,5,6}<?php $min = 100000; // just initialize min with large value. // these values can be hard coded, from JSON, html form, or database // it is just written for illustration $arr = array( 'Mashed Potatoes' => 2, 'Turkey' => 4, 'Pumpkin Pie'=> 4, 'Stuffing'=> 3 ); // we loop through each element of the above array and, // compare its value to the min. foreach($arr as $value){ if( $value < $min){ // If the value is less that min. then we store value into min $min = $value; } } echo 'You can have ' . $min . ' Thanksgiving dinners'; ?> 。性能方面,这是可以的,因为减法并且向阵列添加最低范围是O(N)。