我试图理解用于桶排序的算法,并且我发现如果没有正确的分布模型,我们可以获得O(n ^ 2)的复杂度。相当多的网站的桶数等于数组的大小(比如说' n')并使用算法
std::vector<float> bucket[n];
for (int i = 0; i<n; i++){
bucket[(array[i]*n)/(MAX_ELEMENT_IN_INPUT_ARRAY+1)].push_back(array[i]);
}
我知道整数可以是随机的,并且没有完美的散列算法,但我不太了解上述算法如何将元素分配到各自的桶中。我是否错过了一个直截了当的逻辑?
答案 0 :(得分:1)
以上代码不保证均匀分布。例如,假设您有一个由n个元素组成的输入数组,数字为1,2,4,8,16,32,...,2 n-1 。现在,让我们考虑一下这些元素的最终结果。让我们选择一个元素,比如2 k 。其桶指数由
给出2 k ·n /(2 n-1 + 1)
这里引起警报的原因是1 /(2 n - 1)与n相比是一个非常非常小的数字。因此,我们预计大部分元素将会被分配到非常低的桶数中,并且我们的分散性会很差。
让我们在1,2,4,8,16,32,64,128上尝试一下。我们将总共有8个桶。元素映射如下:
1 * 8 / 129 = 8 / 129 = 0
2 * 8 / 129 = 16 / 129 = 0
4 * 8 / 129 = 32 / 129 = 0
8 * 8 / 129 = 64 / 129 = 0
16 * 8 / 129 = 128 / 129 = 0
32 * 8 / 129 = 256 / 129 = 1
64 * 8 / 129 = 512 / 129 = 3
128 * 8 / 129 = 1024 / 129 = 7
正如您所看到的,这里的八个元素中有五个被放入了存储桶0中,并且大多数存储桶都没有使用。
更一般地说,如果你有这个序列的n个元素,那么只会使用桶n - 1
,(n - 1) / 2
,(n - 1) / 4
,(n - 1) / 8
等。这种形式只有大约log n桶,这意味着关于n - log n个元素将被丢弃到桶0中,并且只有大约log n个元素将存在于其他桶中。
据我所知,没有一个公式可以为您提供良好的分配。如果你假设数字在一个区间内均匀分布,那么这里给出的公式很有效,正如你所看到的,如果你给出指数分布的数字,你最终会得到一个非常糟糕的最坏情况行为。