在C#中计算数组频率分布的最快方法是什么?

时间:2011-08-31 15:14:55

标签: c# algorithm design-patterns data-structures frequency-distribution

我只是想知道这个计算的最佳方法是什么。假设我有一个值的输入数组和边界数组 - 我想计算/ bucketize边界数组中每个段的频率分布。

使用桶搜索是不是一个好主意?

实际上我发现了问题Calculating frequency distribution of a collection with .Net/C#

但是我不明白如何使用桶来达到这个目的,因为在我的情况下每个桶的大小可能会有所不同。

编辑: 在所有讨论之后我都有内部/外部循环解决方案,但是我仍然希望用字典消除内部循环以获得O(n)性能,如果我理解正确的话我需要将输入值散列到存储区索引中。所以我们需要某种具有O(1)复杂度的哈希函数?任何想法怎么做?

2 个答案:

答案 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]++;
  }
}