在 C# 中计算数组频率分布的最快方法是啥?
Posted
技术标签:
【中文标题】在 C# 中计算数组频率分布的最快方法是啥?【英文标题】:What is the fastest way to calculate frequency distribution for array in C#?在 C# 中计算数组频率分布的最快方法是什么? 【发布时间】:2011-11-07 17:21:11 【问题描述】:我只是想知道该计算的最佳方法是什么。假设我有一个输入值数组和边界数组 - 我想计算/分桶边界数组中每个段的频率分布。
使用桶搜索是个好主意吗?
其实我发现了那个问题Calculating frequency distribution of a collection with .Net/C#
但我不明白如何为此目的使用存储桶,因为每个存储桶的大小在我的情况下可能不同。
编辑: 在所有讨论之后,我有内/外循环解决方案,但我仍然想用字典消除内循环以在这种情况下获得 O(n) 性能,如果我理解正确,我需要将输入值散列到存储桶索引中。所以我们需要某种复杂度为 O(1) 的散列函数?有什么想法吗?
【问题讨论】:
你能更好地描述边界数组吗?各种边界之间是否有任何关系(即它们是连续的)还是它们的大小和“位置”完全随机?我假设边界数组完全覆盖了可能值的范围 - 这是真的吗?另外,我假设没有重叠 - 对吧? 最快是大“O”的意思还是小代码的意思?一种简单的方法是自己编写一个函数 Func桶排序已经是 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) 最坏的情况,但您无法超越代码的简单性。在它成为一个真正的问题之前,我不会担心优化。如果你有一个更大的桶数组,你可以使用某种二进制搜索。但是,由于频率分布通常小于 100 个元素,我怀疑您会看到很多实际性能优势。
【讨论】:
您如何看待 BucketizedHashtable 实现,就像它在 Java 中呈现的那样?或者说在执行开始的时候数组排序,有意义吗? 用Dictionary<sometype, int>
消除内部循环以获得摊销的 O(n) 性能。
@Hans 你什么意思?我不太明白:(
@Jevgenij - 据我了解,分桶哈希表通常适用于标准桶大小。这很有效,因为您使用一个输入值并输出存储桶编号的函数,而不是循环遍历存储桶数组。如果转换函数在 O(1) 中运行,那么您可以获得 O(n) 的性能,因为它完全消除了对任何内部循环的要求。这类似于@Hans 通过使用Dictionary<type, int>
所说的话——但它需要某种方法将输入值散列到存储桶索引中。至于数组排序,你只会增加算法的复杂性。
内循环可以用二分查找代替,得到一个整体的O(n*log(m)),其中n - 输入计数; m - 桶数。【参考方案2】:
如果您的输入数组代表真实世界的数据(及其模式),并且边界数组很大以在内部循环中一次又一次地迭代它,您可以考虑以下方法:
首先对输入数组进行排序。如果您使用真实世界的数据 我建议为此考虑 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]++;
【讨论】:
边界用值数组表示。但是复杂性呢?正如我对 Timsort 的理解,在最坏的情况下 O(nlogn) + O(n) 进行循环。我认为二进制搜索的内/外循环应该更好? 不太对。如果中间有一个“空”桶,这将失败。也就是说,排序后的数组中有两个输入值彼此相邻,但进入彼此不相邻的存储桶。但这可以解决。总而言之,这是一个非常好的主意。根据数据,甚至可以使用基数排序,即 O(n),尽管它可能需要大量数据才能使其有价值。但总体运行时间将是一个干净的 O(n)。 P.S.很抱歉发布此文本作为答案。这是一个评论。 @Vilx-,同意并感谢您的纠正。我没有考虑这种情况。以上是关于在 C# 中计算数组频率分布的最快方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章