我只是想知道这个计算的最佳方法是什么。假设我有一个值的输入数组和边界数组 - 我想计算/ bucketize边界数组中每个段的频率分布。
使用桶搜索是不是一个好主意?
实际上我发现了问题Calculating frequency distribution of a collection with .Net/C#
但是我不明白如何使用桶来达到这个目的,因为在我的情况下每个桶的大小可能会有所不同。
编辑: 在所有讨论之后我都有内部/外部循环解决方案,但是我仍然希望用字典消除内部循环以获得O(n)性能,如果我理解正确的话我需要将输入值散列到存储区索引中。所以我们需要某种具有O(1)复杂度的哈希函数?任何想法怎么做?
答案 0 :(得分:4)
Bucket Sort已经是O(n ^ 2)最坏的情况,所以我在这里只做一个简单的内/外循环。由于您的存储桶数组必须比输入数组短,因此请将其保留在内部循环中。由于您使用的是自定义存储桶大小,因此实际上没有可以消除内部循环的数学技巧。
int[] freq = new int[buckets.length - 1];
foreach(int d in input)
{
for(int i = 0; i < buckets.length - 1; i++)
{
if(d >= buckets[i] && d < buckets[i+1])
{
freq[i]++;
break;
}
}
}
这也是O(n ^ 2)最坏的情况,但你无法击败代码的简单性。我不担心优化,直到它成为一个真正的问题。如果你有一个更大的桶阵列,你可以使用某种二进制搜索。但是,由于频率分布通常<1。 100个元素,我怀疑你会看到很多真实的性能优势。
答案 1 :(得分:1)
如果输入数组表示真实世界数据(带有模式),并且边界数组很大,可以在内循环中反复迭代它,您可以考虑以下方法:
首先对输入数组进行排序。如果您使用真实数据 我建议您考虑 Timsort - Wiki 。它 为可以看到的模式提供非常好的性能保证 现实世界的数据。
遍历排序数组并将其与边界数组中的第一个值进行比较:
在代码中它看起来像这样:
Timsort(myArray);
int boundPos;
boundaries = GetBoundaries(); //assume the boundaries is a Dictionary<int,int>()
for (int i = 0; i<myArray.Lenght; i++) {
if (myArray[i]<boundaries[boundPos]) {
boundaries[boubdPos]++;
}
else {
boundPos++;
boundaries[boubdPos]++;
}
}